aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/tests
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/tests')
-rw-r--r--sys/contrib/openzfs/tests/runfiles/common.run45
-rw-r--r--sys/contrib/openzfs/tests/runfiles/linux.run6
-rw-r--r--sys/contrib/openzfs/tests/runfiles/sanity.run6
-rwxr-xr-xsys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in61
-rwxr-xr-xsys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/crypto_test.c3
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg6
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib56
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg4
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am32
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh75
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_tunables.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/cleanup.ksh43
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/setup.ksh50
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/zfs_send_test.ksh111
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/library.kshlib80
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_label_repair_001.ksh15
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_metaslab_leak.ksh70
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib42
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_create.ksh (renamed from sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_010_pos.ksh)101
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh204
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh126
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh30
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh32
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib235
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh90
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh80
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_date_range_002.ksh76
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcstat_001_pos.ksh (renamed from sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arcstat_001_pos.ksh)2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcsummary_001_pos.ksh (renamed from sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_001_pos.ksh)10
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcsummary_002_neg.ksh (renamed from sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_002_neg.ksh)6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/cleanup.ksh43
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/setup.ksh50
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/zfs_send_usertest.ksh145
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib6
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_degraded_sit_out.ksh106
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out.ksh102
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out_neg.ksh116
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_synchronous_zedlet.ksh149
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_002_pos.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/fault_limits.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/suspend_on_probe_errors.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/mount/mount_loopback.ksh111
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh46
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/attach_resilver_sit_out.ksh189
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/replace_resilver_sit_out.ksh199
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh14
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh53
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh40
51 files changed, 2884 insertions, 196 deletions
diff --git a/sys/contrib/openzfs/tests/runfiles/common.run b/sys/contrib/openzfs/tests/runfiles/common.run
index 2da46458289a..9f531411fbe1 100644
--- a/sys/contrib/openzfs/tests/runfiles/common.run
+++ b/sys/contrib/openzfs/tests/runfiles/common.run
@@ -168,10 +168,10 @@ tags = ['functional', 'cli_root', 'zinject']
tests = ['zdb_002_pos', 'zdb_003_pos', 'zdb_004_pos', 'zdb_005_pos',
'zdb_006_pos', 'zdb_args_neg', 'zdb_args_pos',
'zdb_block_size_histogram', 'zdb_checksum', 'zdb_decompress',
- 'zdb_display_block', 'zdb_encrypted', 'zdb_label_checksum',
- 'zdb_object_range_neg', 'zdb_object_range_pos', 'zdb_objset_id',
- 'zdb_decompress_zstd', 'zdb_recover', 'zdb_recover_2', 'zdb_backup',
- 'zdb_tunables']
+ 'zdb_display_block', 'zdb_encrypted', 'zdb_encrypted_raw',
+ 'zdb_label_checksum', 'zdb_object_range_neg', 'zdb_object_range_pos',
+ 'zdb_objset_id', 'zdb_decompress_zstd', 'zdb_recover', 'zdb_recover_2',
+ 'zdb_backup', 'zdb_tunables']
pre =
post =
tags = ['functional', 'cli_root', 'zdb']
@@ -323,6 +323,10 @@ tests = ['zfs_send_001_pos', 'zfs_send_002_pos', 'zfs_send_003_pos',
'zfs_send_raw', 'zfs_send_sparse', 'zfs_send-b', 'zfs_send_skip_missing']
tags = ['functional', 'cli_root', 'zfs_send']
+[tests/functional/cli_root/zfs_send_delegation]
+tests = ['zfs_send_test']
+tags = ['functional', 'cli_root', 'zfs_send_delegation']
+
[tests/functional/cli_root/zfs_set]
tests = ['cache_001_pos', 'cache_002_neg', 'canmount_001_pos',
'canmount_002_pos', 'canmount_003_pos', 'canmount_004_pos',
@@ -379,7 +383,7 @@ tags = ['functional', 'cli_root', 'zfs_wait']
[tests/functional/cli_root/zhack]
tests = ['zhack_label_repair_001', 'zhack_label_repair_002',
- 'zhack_label_repair_003', 'zhack_label_repair_004']
+ 'zhack_label_repair_003', 'zhack_label_repair_004', 'zhack_metaslab_leak']
pre =
post =
tags = ['functional', 'cli_root', 'zhack']
@@ -391,8 +395,9 @@ tags = ['functional', 'cli_root', 'zpool']
[tests/functional/cli_root/zpool_add]
tests = ['zpool_add_001_pos', 'zpool_add_002_pos', 'zpool_add_003_pos',
'zpool_add_004_pos', 'zpool_add_006_pos', 'zpool_add_007_neg',
- 'zpool_add_008_neg', 'zpool_add_009_neg', 'zpool_add_010_pos',
- 'add-o_ashift', 'add_prop_ashift', 'zpool_add_dryrun_output']
+ 'zpool_add_008_neg', 'zpool_add_009_neg', 'zpool_add_warn_create',
+ 'zpool_add_warn_degraded', 'zpool_add_warn_removal', 'add-o_ashift',
+ 'add_prop_ashift', 'zpool_add_dryrun_output']
tags = ['functional', 'cli_root', 'zpool_add']
[tests/functional/cli_root/zpool_attach]
@@ -486,6 +491,10 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos',
tags = ['functional', 'cli_root', 'zpool_import']
timeout = 1200
+[tests/functional/cli_root/zpool_iostat]
+tests = ['zpool_iostat_interval_all', 'zpool_iostat_interval_some']
+tags = ['functional', 'cli_root', 'zpool_iostat']
+
[tests/functional/cli_root/zpool_labelclear]
tests = ['zpool_labelclear_active', 'zpool_labelclear_exported',
'zpool_labelclear_removed', 'zpool_labelclear_valid']
@@ -546,7 +555,7 @@ tests = ['zpool_scrub_001_neg', 'zpool_scrub_002_pos', 'zpool_scrub_003_pos',
'zpool_scrub_multiple_pools',
'zpool_error_scrub_001_pos', 'zpool_error_scrub_002_pos',
'zpool_error_scrub_003_pos', 'zpool_error_scrub_004_pos',
- 'zpool_scrub_date_range_001']
+ 'zpool_scrub_date_range_001', 'zpool_scrub_date_range_002']
tags = ['functional', 'cli_root', 'zpool_scrub']
[tests/functional/cli_root/zpool_set]
@@ -624,8 +633,8 @@ tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
'zpool_history_001_neg', 'zpool_import_001_neg', 'zpool_import_002_neg',
'zpool_offline_001_neg', 'zpool_online_001_neg', 'zpool_remove_001_neg',
'zpool_replace_001_neg', 'zpool_scrub_001_neg', 'zpool_set_001_neg',
- 'zpool_status_001_neg', 'zpool_upgrade_001_neg', 'arcstat_001_pos',
- 'arc_summary_001_pos', 'arc_summary_002_neg', 'zpool_wait_privilege',
+ 'zpool_status_001_neg', 'zpool_upgrade_001_neg', 'zarcstat_001_pos',
+ 'zarcsummary_001_pos', 'zarcsummary_002_neg', 'zpool_wait_privilege',
'zilstat_001_pos']
user =
tags = ['functional', 'cli_user', 'misc']
@@ -637,6 +646,10 @@ tests = ['zfs_list_001_pos', 'zfs_list_002_pos', 'zfs_list_003_pos',
user =
tags = ['functional', 'cli_user', 'zfs_list']
+[tests/functional/cli_user/zfs_send_delegation_user]
+tests = ['zfs_send_usertest']
+tags = ['functional', 'cli_user', 'zfs_send_delegation_user']
+
[tests/functional/cli_user/zpool_iostat]
tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos',
'zpool_iostat_003_neg', 'zpool_iostat_004_pos',
@@ -940,10 +953,11 @@ tags = ['functional', 'rename_dirs']
[tests/functional/replacement]
tests = ['attach_import', 'attach_multiple', 'attach_rebuild',
- 'attach_resilver', 'detach', 'rebuild_disabled_feature',
- 'rebuild_multiple', 'rebuild_raidz', 'replace_import', 'replace_rebuild',
- 'replace_resilver', 'resilver_restart_001', 'resilver_restart_002',
- 'scrub_cancel']
+ 'attach_resilver', 'attach_resilver_sit_out', 'detach',
+ 'rebuild_disabled_feature', 'rebuild_multiple', 'rebuild_raidz',
+ 'replace_import', 'replace_rebuild', 'replace_resilver',
+ 'replace_resilver_sit_out', 'resilver_restart_001',
+ 'resilver_restart_002', 'scrub_cancel']
tags = ['functional', 'replacement']
[tests/functional/reservation]
@@ -1076,7 +1090,8 @@ tags = ['functional', 'write_dirs']
[tests/functional/xattr]
tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos',
'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg',
- 'xattr_011_pos', 'xattr_012_pos', 'xattr_013_pos', 'xattr_compat']
+ 'xattr_011_pos', 'xattr_012_pos', 'xattr_013_pos', 'xattr_014_pos',
+ 'xattr_compat']
tags = ['functional', 'xattr']
[tests/functional/zvol/zvol_ENOSPC]
diff --git a/sys/contrib/openzfs/tests/runfiles/linux.run b/sys/contrib/openzfs/tests/runfiles/linux.run
index f3d56acffde0..339361cc2762 100644
--- a/sys/contrib/openzfs/tests/runfiles/linux.run
+++ b/sys/contrib/openzfs/tests/runfiles/linux.run
@@ -109,7 +109,9 @@ tags = ['functional', 'direct']
[tests/functional/events:Linux]
tests = ['events_001_pos', 'events_002_pos', 'zed_rc_filter', 'zed_fd_spill',
'zed_cksum_reported', 'zed_cksum_config', 'zed_io_config',
- 'zed_slow_io', 'zed_slow_io_many_vdevs', 'zed_diagnose_multiple']
+ 'zed_slow_io', 'zed_slow_io_many_vdevs', 'zed_diagnose_multiple',
+ 'zed_synchronous_zedlet', 'slow_vdev_sit_out', 'slow_vdev_sit_out_neg',
+ 'slow_vdev_degraded_sit_out']
tags = ['functional', 'events']
[tests/functional/fallocate:Linux]
@@ -161,7 +163,7 @@ tests = ['mmp_on_thread', 'mmp_on_uberblocks', 'mmp_on_off', 'mmp_interval',
tags = ['functional', 'mmp']
[tests/functional/mount:Linux]
-tests = ['umount_unlinked_drain']
+tests = ['umount_unlinked_drain', 'mount_loopback']
tags = ['functional', 'mount']
[tests/functional/pam:Linux]
diff --git a/sys/contrib/openzfs/tests/runfiles/sanity.run b/sys/contrib/openzfs/tests/runfiles/sanity.run
index 7767c0c2d535..249b415029c4 100644
--- a/sys/contrib/openzfs/tests/runfiles/sanity.run
+++ b/sys/contrib/openzfs/tests/runfiles/sanity.run
@@ -400,8 +400,8 @@ tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
'zpool_detach_001_neg', 'zpool_export_001_neg', 'zpool_get_001_neg',
'zpool_history_001_neg', 'zpool_offline_001_neg', 'zpool_online_001_neg',
'zpool_remove_001_neg', 'zpool_scrub_001_neg', 'zpool_set_001_neg',
- 'zpool_status_001_neg', 'zpool_upgrade_001_neg', 'arcstat_001_pos',
- 'arc_summary_001_pos', 'arc_summary_002_neg', 'zpool_wait_privilege',
+ 'zpool_status_001_neg', 'zpool_upgrade_001_neg', 'zarcstat_001_pos',
+ 'zarcsummary_001_pos', 'zarcsummary_002_neg', 'zpool_wait_privilege',
'zilstat_001_pos']
user =
tags = ['functional', 'cli_user', 'misc']
@@ -622,7 +622,7 @@ tags = ['functional', 'vdev_zaps']
[tests/functional/xattr]
tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos',
'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg',
- 'xattr_011_pos', 'xattr_013_pos', 'xattr_compat']
+ 'xattr_011_pos', 'xattr_013_pos', 'xattr_014_pos', 'xattr_compat']
tags = ['functional', 'xattr']
[tests/functional/zvol/zvol_ENOSPC]
diff --git a/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in b/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in
index 2158208be6e5..d2c1185e4a94 100755
--- a/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in
+++ b/sys/contrib/openzfs/tests/test-runner/bin/test-runner.py.in
@@ -34,6 +34,7 @@ from select import select
from subprocess import PIPE
from subprocess import Popen
from subprocess import check_output
+from subprocess import run
from threading import Timer
from time import time, CLOCK_MONOTONIC
from os.path import exists
@@ -187,6 +188,63 @@ User: %s
''' % (self.pathname, self.identifier, self.outputdir, self.timeout, self.user)
def kill_cmd(self, proc, options, kmemleak, keyboard_interrupt=False):
+
+ """
+ We're about to kill a command due to a timeout.
+ If we're running with the -O option, then dump debug info about the
+ process with the highest CPU usage to /dev/kmsg (Linux only). This can
+ help debug the timeout.
+
+ Debug info includes:
+ - 30 lines from 'top'
+ - /proc/<PID>/stack output of process with highest CPU usage
+ - Last lines strace-ing process with highest CPU usage
+ """
+ if exists("/dev/kmsg"):
+ c = """
+TOP_OUT="$(COLUMNS=160 top -b -n 1 | head -n 30)"
+read -r PID CMD <<< $(echo "$TOP_OUT" | /usr/bin/awk \
+"/COMMAND/{
+ print_next=1
+ next
+}
+{
+ if (print_next == 1) {
+ print \\$1\\" \\"\\$12
+ exit
+ }
+}")
+echo "##### ZTS timeout debug #####"
+echo "----- top -----"
+echo "$TOP_OUT"
+echo "----- /proc/$PID/stack ($CMD)) -----"
+cat /proc/$PID/stack
+echo "----- strace ($CMD) -----"
+TMPFILE="$(mktemp --suffix=ZTS)"
+/usr/bin/strace -k --stack-traces -p $PID &> "$TMPFILE" &
+sleep 0.1
+killall strace
+tail -n 30 $TMPFILE
+rm "$TMPFILE"
+echo "##### /proc/sysrq-trigger stack #####"
+"""
+ c = "sudo bash -c '" + c + "'"
+ data = run(c, capture_output=True, shell=True, text=True)
+ out = data.stdout
+ try:
+ kp = Popen([SUDO, "sh", "-c",
+ "echo '" + out + "' > /dev/kmsg"])
+ kp.wait()
+
+ """
+ Trigger kernel stack traces
+ """
+ kp = Popen([SUDO, "sh", "-c",
+ "echo l > /proc/sysrq-trigger"])
+ kp.wait()
+ except Exception:
+ pass
+
"""
Kill a running command due to timeout, or ^C from the keyboard. If
sudo is required, this user was verified previously.
@@ -1129,6 +1187,9 @@ def parse_args():
parser.add_option('-o', action='callback', callback=options_cb,
default=BASEDIR, dest='outputdir', type='string',
metavar='outputdir', help='Specify an output directory.')
+ parser.add_option('-O', action='store_true', default=False,
+ dest='timeout_debug',
+ help='Dump debugging info to /dev/kmsg on test timeout')
parser.add_option('-i', action='callback', callback=options_cb,
default=TESTDIR, dest='testdir', type='string',
metavar='testdir', help='Specify a test directory.')
diff --git a/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in b/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
index 001970120148..5bc65f993734 100755
--- a/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
+++ b/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
@@ -232,7 +232,7 @@ maybe = {
'cli_root/zpool_trim/zpool_trim_fault_export_import_online':
['FAIL', known_reason],
'cli_root/zpool_upgrade/zpool_upgrade_004_pos': ['FAIL', 6141],
- 'cli_user/misc/arc_summary_001_pos': ['FAIL', known_reason],
+ 'cli_user/misc/zarcsummary_001_pos': ['FAIL', known_reason],
'delegate/setup': ['SKIP', exec_reason],
'events/zed_cksum_config': ['FAIL', known_reason],
'fault/auto_replace_002_pos': ['FAIL', known_reason],
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/crypto_test.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/crypto_test.c
index cbebd33e0bf6..c8d8622c7571 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/crypto_test.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/crypto_test.c
@@ -863,7 +863,8 @@ test_result(const crypto_test_t *test, int encrypt_rv, uint8_t *encrypt_buf,
return (pass);
/* print summary of test result */
- printf("%s[%lu]: encrypt=%s decrypt=%s\n", test->fileloc, test->id,
+ printf("%s[%ju]: encrypt=%s decrypt=%s\n", test->fileloc,
+ (uintmax_t)test->id,
encrypt_pass ? "PASS" : "FAIL",
decrypt_pass ? "PASS" : "FAIL");
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg b/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
index 884a99d785bc..1c4d25e152a7 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
@@ -100,6 +100,7 @@ export SYSTEM_FILES_COMMON='awk
uniq
vmstat
wc
+ which
xargs
xxh128sum'
@@ -146,6 +147,7 @@ export SYSTEM_FILES_LINUX='attr
lscpu
lsmod
lsscsi
+ mkfs.xfs
mkswap
modprobe
mountpoint
@@ -169,8 +171,8 @@ export ZFS_FILES='zdb
zpool
ztest
raidz_test
- arc_summary
- arcstat
+ zarcsummary
+ zarcstat
zilstat
dbufstat
mount.zfs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib b/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib
index 23e89599cae0..8b30b9b91641 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/libtest.shlib
@@ -1085,7 +1085,7 @@ function fill_fs # destdir dirnum filenum bytes num_writes data
typeset -i filenum=${3:-50}
typeset -i bytes=${4:-8192}
typeset -i num_writes=${5:-10240}
- typeset data=${6:-0}
+ typeset data=${6:-"R"}
mkdir -p $destdir/{1..$dirnum}
for f in $destdir/{1..$dirnum}/$TESTFILE{1..$filenum}; do
@@ -1112,6 +1112,16 @@ function get_pool_prop # property pool
zpool get -Hpo value "$prop" "$pool" || log_fail "zpool get $prop $pool"
}
+# Get the specified vdev property in parsable format or fail
+function get_vdev_prop
+{
+ typeset prop="$1"
+ typeset pool="$2"
+ typeset vdev="$3"
+
+ zpool get -Hpo value "$prop" "$pool" "$vdev" || log_fail "zpool get $prop $pool $vdev"
+}
+
# Return 0 if a pool exists; $? otherwise
#
# $1 - pool name
@@ -1971,6 +1981,28 @@ function wait_vdev_state # pool disk state timeout
}
#
+# Wait for vdev 'sit_out' property to be cleared.
+#
+# $1 pool name
+# $2 vdev name
+# $3 timeout
+#
+function wait_sit_out #pool vdev timeout
+{
+ typeset pool=${1:-$TESTPOOL}
+ typeset vdev="$2"
+ typeset timeout=${3:-300}
+ for (( timer = 0; timer < $timeout; timer++ )); do
+ if [ "$(get_vdev_prop sit_out "$pool" "$vdev")" = "off" ]; then
+ return 0
+ fi
+ sleep 1;
+ done
+
+ return 1
+}
+
+#
# Check the output of 'zpool status -v <pool>',
# and to see if the content of <token> contain the <keyword> specified.
#
@@ -2881,6 +2913,28 @@ function user_run
log_note "user: $user"
log_note "cmd: $*"
+ if ! sudo -Eu $user test -x $PATH ; then
+ log_note "-------------------------------------------------"
+ log_note "Warning: $user doesn't have permissions on $PATH"
+ log_note ""
+ log_note "This usually happens when you're running ZTS locally"
+ log_note "from inside the ZFS source dir, and are attempting to"
+ log_note "run a test that calls user_run. The ephemeral user"
+ log_note "($user) that ZTS is creating does not have permission"
+ log_note "to traverse to $PATH, or the binaries in $PATH are"
+ log_note "not the right permissions."
+ log_note ""
+ log_note "To get around this, copy your ZFS source directory"
+ log_note "to a world-accessible location (like /tmp), and "
+ log_note "change the permissions on your ZFS source dir "
+ log_note "to allow access."
+ log_note ""
+ log_note "Also, verify that /dev/zfs is RW for others:"
+ log_note ""
+ log_note " sudo chmod o+rw /dev/zfs"
+ log_note "-------------------------------------------------"
+ fi
+
typeset out=$TEST_BASE_DIR/out
typeset err=$TEST_BASE_DIR/err
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg b/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg
index e273c9f85c28..127ea188f17f 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/tunables.cfg
@@ -72,6 +72,9 @@ MULTIHOST_INTERVAL multihost.interval zfs_multihost_interval
OVERRIDE_ESTIMATE_RECORDSIZE send.override_estimate_recordsize zfs_override_estimate_recordsize
PREFETCH_DISABLE prefetch.disable zfs_prefetch_disable
RAIDZ_EXPAND_MAX_REFLOW_BYTES vdev.expand_max_reflow_bytes raidz_expand_max_reflow_bytes
+READ_SIT_OUT_SECS vdev.read_sit_out_secs vdev_read_sit_out_secs
+SIT_OUT_CHECK_INTERVAL vdev.raidz_outlier_check_interval_ms vdev_raidz_outlier_check_interval_ms
+SIT_OUT_INSENSITIVITY vdev.raidz_outlier_insensitivity vdev_raidz_outlier_insensitivity
REBUILD_SCRUB_ENABLED rebuild_scrub_enabled zfs_rebuild_scrub_enabled
REMOVAL_SUSPEND_PROGRESS removal_suspend_progress zfs_removal_suspend_progress
REMOVE_MAX_SEGMENT remove_max_segment zfs_remove_max_segment
@@ -88,6 +91,7 @@ SPA_DISCARD_MEMORY_LIMIT spa.discard_memory_limit zfs_spa_discard_memory_limit
SPA_LOAD_VERIFY_DATA spa.load_verify_data spa_load_verify_data
SPA_LOAD_VERIFY_METADATA spa.load_verify_metadata spa_load_verify_metadata
SPA_NOTE_TXG_TIME spa.note_txg_time spa_note_txg_time
+SPA_FLUSH_TXG_TIME spa.flush_txg_time spa_flush_txg_time
TRIM_EXTENT_BYTES_MIN trim.extent_bytes_min zfs_trim_extent_bytes_min
TRIM_METASLAB_SKIP trim.metaslab_skip zfs_trim_metaslab_skip
TRIM_TXG_BATCH trim.txg_batch zfs_trim_txg_batch
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
index 41e7b45ef4ec..678c01b58f94 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
@@ -197,6 +197,7 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \
functional/cli_root/zpool_import/blockfiles/unclean_export.dat.bz2 \
functional/cli_root/zpool_import/zpool_import.cfg \
functional/cli_root/zpool_import/zpool_import.kshlib \
+ functional/cli_root/zpool_iostat/zpool_iostat.kshlib \
functional/cli_root/zpool_initialize/zpool_initialize.kshlib \
functional/cli_root/zpool_labelclear/labelclear.cfg \
functional/cli_root/zpool_remove/zpool_remove.cfg \
@@ -640,6 +641,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zdb/zdb_decompress_zstd.ksh \
functional/cli_root/zdb/zdb_display_block.ksh \
functional/cli_root/zdb/zdb_encrypted.ksh \
+ functional/cli_root/zdb/zdb_encrypted_raw.ksh \
functional/cli_root/zdb/zdb_label_checksum.ksh \
functional/cli_root/zdb/zdb_object_range_neg.ksh \
functional/cli_root/zdb/zdb_object_range_pos.ksh \
@@ -892,6 +894,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zfs_send/zfs_send_raw.ksh \
functional/cli_root/zfs_send/zfs_send_skip_missing.ksh \
functional/cli_root/zfs_send/zfs_send_sparse.ksh \
+ functional/cli_root/zfs_send_delegation/cleanup.ksh \
+ functional/cli_root/zfs_send_delegation/setup.ksh \
+ functional/cli_root/zfs_send_delegation/zfs_send_test.ksh \
functional/cli_root/zfs_set/cache_001_pos.ksh \
functional/cli_root/zfs_set/cache_002_neg.ksh \
functional/cli_root/zfs_set/canmount_001_pos.ksh \
@@ -1009,6 +1014,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zhack/zhack_label_repair_002.ksh \
functional/cli_root/zhack/zhack_label_repair_003.ksh \
functional/cli_root/zhack/zhack_label_repair_004.ksh \
+ functional/cli_root/zhack/zhack_metaslab_leak.ksh \
functional/cli_root/zpool_add/add_nested_replacing_spare.ksh \
functional/cli_root/zpool_add/add-o_ashift.ksh \
functional/cli_root/zpool_add/add_prop_ashift.ksh \
@@ -1023,7 +1029,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_add/zpool_add_007_neg.ksh \
functional/cli_root/zpool_add/zpool_add_008_neg.ksh \
functional/cli_root/zpool_add/zpool_add_009_neg.ksh \
- functional/cli_root/zpool_add/zpool_add_010_pos.ksh \
+ functional/cli_root/zpool_add/zpool_add_warn_create.ksh \
+ functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh \
+ functional/cli_root/zpool_add/zpool_add_warn_removal.ksh \
functional/cli_root/zpool_add/zpool_add_dryrun_output.ksh \
functional/cli_root/zpool_attach/attach-o_ashift.ksh \
functional/cli_root/zpool_attach/cleanup.ksh \
@@ -1174,6 +1182,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_import/zpool_import_parallel_admin.ksh \
functional/cli_root/zpool_import/zpool_import_parallel_neg.ksh \
functional/cli_root/zpool_import/zpool_import_parallel_pos.ksh \
+ functional/cli_root/zpool_iostat/setup.ksh \
+ functional/cli_root/zpool_iostat/cleanup.ksh \
+ functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh \
+ functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh \
functional/cli_root/zpool_initialize/cleanup.ksh \
functional/cli_root/zpool_initialize/zpool_initialize_attach_detach_add_remove.ksh \
functional/cli_root/zpool_initialize/zpool_initialize_fault_export_import_online.ksh \
@@ -1247,6 +1259,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool_scrub/zpool_scrub_print_repairing.ksh \
functional/cli_root/zpool_scrub/zpool_scrub_txg_continue_from_last.ksh \
functional/cli_root/zpool_scrub/zpool_scrub_date_range_001.ksh \
+ functional/cli_root/zpool_scrub/zpool_scrub_date_range_002.ksh \
functional/cli_root/zpool_scrub/zpool_error_scrub_001_pos.ksh \
functional/cli_root/zpool_scrub/zpool_error_scrub_002_pos.ksh \
functional/cli_root/zpool_scrub/zpool_error_scrub_003_pos.ksh \
@@ -1351,9 +1364,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_root/zpool/zpool_002_pos.ksh \
functional/cli_root/zpool/zpool_003_pos.ksh \
functional/cli_root/zpool/zpool_colors.ksh \
- functional/cli_user/misc/arcstat_001_pos.ksh \
- functional/cli_user/misc/arc_summary_001_pos.ksh \
- functional/cli_user/misc/arc_summary_002_neg.ksh \
+ functional/cli_user/misc/zarcstat_001_pos.ksh \
+ functional/cli_user/misc/zarcsummary_001_pos.ksh \
+ functional/cli_user/misc/zarcsummary_002_neg.ksh \
functional/cli_user/misc/zilstat_001_pos.ksh \
functional/cli_user/misc/cleanup.ksh \
functional/cli_user/misc/setup.ksh \
@@ -1408,6 +1421,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/cli_user/zfs_list/zfs_list_005_neg.ksh \
functional/cli_user/zfs_list/zfs_list_007_pos.ksh \
functional/cli_user/zfs_list/zfs_list_008_neg.ksh \
+ functional/cli_user/zfs_send_delegation_user/cleanup.ksh \
+ functional/cli_user/zfs_send_delegation_user/setup.ksh \
+ functional/cli_user/zfs_send_delegation_user/zfs_send_usertest.ksh \
functional/cli_user/zpool_iostat/cleanup.ksh \
functional/cli_user/zpool_iostat/setup.ksh \
functional/cli_user/zpool_iostat/zpool_iostat_001_neg.ksh \
@@ -1524,6 +1540,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/events/events_001_pos.ksh \
functional/events/events_002_pos.ksh \
functional/events/setup.ksh \
+ functional/events/slow_vdev_degraded_sit_out.ksh \
+ functional/events/slow_vdev_sit_out.ksh \
+ functional/events/slow_vdev_sit_out_neg.ksh \
functional/events/zed_cksum_config.ksh \
functional/events/zed_cksum_reported.ksh \
functional/events/zed_diagnose_multiple.ksh \
@@ -1532,6 +1551,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/events/zed_rc_filter.ksh \
functional/events/zed_slow_io.ksh \
functional/events/zed_slow_io_many_vdevs.ksh \
+ functional/events/zed_synchronous_zedlet.ksh \
functional/exec/cleanup.ksh \
functional/exec/exec_001_pos.ksh \
functional/exec/exec_002_neg.ksh \
@@ -1706,6 +1726,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/mmp/setup.ksh \
functional/mount/cleanup.ksh \
functional/mount/setup.ksh \
+ functional/mount/mount_loopback.ksh \
functional/mount/umount_001.ksh \
functional/mount/umountall_001.ksh \
functional/mount/umount_unlinked_drain.ksh \
@@ -1935,6 +1956,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/replacement/attach_multiple.ksh \
functional/replacement/attach_rebuild.ksh \
functional/replacement/attach_resilver.ksh \
+ functional/replacement/attach_resilver_sit_out.ksh \
functional/replacement/cleanup.ksh \
functional/replacement/detach.ksh \
functional/replacement/rebuild_disabled_feature.ksh \
@@ -1943,6 +1965,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/replacement/replace_import.ksh \
functional/replacement/replace_rebuild.ksh \
functional/replacement/replace_resilver.ksh \
+ functional/replacement/replace_resilver_sit_out.ksh \
functional/replacement/resilver_restart_001.ksh \
functional/replacement/resilver_restart_002.ksh \
functional/replacement/scrub_cancel.ksh \
@@ -2211,6 +2234,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/xattr/xattr_011_pos.ksh \
functional/xattr/xattr_012_pos.ksh \
functional/xattr/xattr_013_pos.ksh \
+ functional/xattr/xattr_014_pos.ksh \
functional/xattr/xattr_compat.ksh \
functional/zap_shrink/cleanup.ksh \
functional/zap_shrink/zap_shrink_001_pos.ksh \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh
new file mode 100755
index 000000000000..85d267d5402f
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_encrypted_raw.ksh
@@ -0,0 +1,75 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2023, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib
+
+#
+# DESCRIPTION:
+# 'zdb -K ...' should enable reading from a raw-encrypted dataset
+#
+# STRATEGY:
+# 1. Create an encrypted dataset
+# 2. Write some data to a file
+# 3. Run zdb -dddd on the file, confirm it can't be read
+# 4. Run zdb -K ... -ddddd on the file, confirm it can be read
+#
+
+verify_runnable "both"
+
+dataset="$TESTPOOL/$TESTFS2"
+file="$TESTDIR2/somefile"
+keyfile="$TEST_BASE_DIR/keyfile"
+
+function cleanup
+{
+ datasetexists "$dataset" && destroy_dataset "$dataset" -f
+ rm -f "$keyfile"
+ default_cleanup_noexit
+}
+
+log_onexit cleanup
+
+log_must default_setup_noexit $DISKS
+
+log_assert "'zdb -K' should enable reading from a raw-encrypted dataset"
+
+# The key must be 32 bytes long.
+echo -n "$RAWKEY" > "$keyfile"
+
+log_must zfs create -o mountpoint="$TESTDIR2" \
+ -o encryption=on -o keyformat=raw -o keylocation="file://$keyfile" \
+ "$dataset"
+
+echo 'my great encrypted text' > "$file"
+
+typeset -i obj=$(ls -i "$file" | cut -d' ' -f1)
+typeset -i size=$(wc -c < "$file")
+
+log_note "test file $file is objid $obj, size $size"
+
+sync_pool "$TESTPOOL" true
+
+log_must eval "zdb -dddd $dataset $obj | grep -q 'object encrypted'"
+
+log_must eval "zdb -K $keyfile -dddd $dataset $obj | grep -q 'size\s$size$'"
+
+log_pass "'zdb -K' enables reading from a raw-encrypted dataset"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_tunables.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_tunables.ksh
index 46965aa7cc37..b89790d5d525 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_tunables.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_tunables.ksh
@@ -63,7 +63,7 @@ log_mustnot_expect 'no such tunable: 0' zdb -o show=0
log_mustnot_expect 'no such tunable: 1' zdb -o info=1
# can set multiple in same command
-log_must eval 'zdb -o zfs_recover=1 -o zfs_flags=512 | xargs | grep -qE "^zfs_recover: 0 -> 1 zfs_flags: 4294965758 -> 512$"'
+log_must eval 'zdb -o zfs_recover=1 -o zfs_flags=512 | xargs | grep -qE "^zfs_recover: 0 -> 1 zfs_flags: 4294932990 -> 512$"'
# can set and show in same command
log_must eval 'zdb -o zfs_recover=1 -o zfs_recover -o zfs_recover=0 | xargs | grep -qE "^zfs_recover: 0 -> 1 zfs_recover: 1 zfs_recover: 1 -> 0$"'
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/cleanup.ksh
new file mode 100755
index 000000000000..4a59e15cc693
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/cleanup.ksh
@@ -0,0 +1,43 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+
+poolexists $TESTPOOL1 && \
+ destroy_pool $TESTPOOL1
+
+del_user $STAFF1
+del_user $STAFF2
+del_group $STAFF_GROUP
+
+del_user $OTHER1
+del_user $OTHER2
+del_group $OTHER_GROUP
+
+default_cleanup
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/setup.ksh
new file mode 100755
index 000000000000..0978193eddc4
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/setup.ksh
@@ -0,0 +1,50 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+# Create staff group and add two user to it
+log_must add_group $STAFF_GROUP
+if ! id $STAFF1 > /dev/null 2>&1; then
+ log_must add_user $STAFF_GROUP $STAFF1
+fi
+if ! id $STAFF2 > /dev/null 2>&1; then
+ log_must add_user $STAFF_GROUP $STAFF2
+fi
+
+# Create other group and add two user to it
+log_must add_group $OTHER_GROUP
+if ! id $OTHER1 > /dev/null 2>&1; then
+ log_must add_user $OTHER_GROUP $OTHER1
+fi
+if ! id $OTHER2 > /dev/null 2>&1; then
+ log_must add_user $OTHER_GROUP $OTHER2
+fi
+DISK=${DISKS%% *}
+
+default_raidz_setup $DISKS
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/zfs_send_test.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/zfs_send_test.ksh
new file mode 100755
index 000000000000..d018f313fae1
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_send_delegation/zfs_send_test.ksh
@@ -0,0 +1,111 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara Inc.
+#
+
+# STRATEGY:
+# 1. Create a pool (this is done by the test framework)
+# 2. Create an encrypted dataset
+# 3. Write random data to the encrypted dataset
+# 4. Snapshot the dataset
+# 5. As root: attempt a send and raw send (both should succeed)
+# 6. Create a delegation (zfs allow -u user send testpool/encrypted_dataset)
+# 7. As root: attempt a send and raw send (both should succeed)
+# 8. Create a delegation (zfs allow -u user send:raw testpool/encrypted_dataset)
+# 9. As root: attempt a send and raw send (both should succeed)
+# 10. Disable delegation (zfs unallow)
+# 11. As root: attempt a send and raw send (both should succeed)
+# 12. Clean up (handled by framework)
+#
+# Tested as a user under ../cli_user/zfs_send_delegation_user/
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib
+. $STF_SUITE/tests/functional/delegate/delegate.cfg
+
+# create encrypted dataset
+
+log_must eval "echo $PASSPHRASE | zfs create -o encryption=on -o keyformat=passphrase $TESTPOOL/$TESTFS1"
+
+# create target dataset for receives
+if ! zfs list | grep testfs2 >/dev/null 2>&1; then
+ dataset_created="TRUE"
+ log_must zfs create $TESTPOOL/$TESTFS2
+fi
+
+# create user and group
+typeset perms="snapshot,reservation,compression,checksum,userprop,receive"
+
+log_note "Added permissions to the $OTHER1 user."
+log_must zfs allow $OTHER1 $perms $TESTPOOL/$TESTFS1
+log_must zfs allow $OTHER1 $perms $TESTPOOL/$TESTFS2
+
+# create random data
+log_must fill_fs $TESTPOOL/$TESTFS1/child 1 2047 1024 1 R
+
+# snapshot
+log_must zfs snapshot $TESTPOOL/$TESTFS1@snap1
+
+
+# check baseline send abilities (should pass)
+log_must eval "zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv0_datastream.$$"
+log_must eval "zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv0raw_datastream.$$"
+
+
+# create delegation
+log_must zfs allow $OTHER1 send $TESTPOOL/$TESTFS1
+
+# attempt send with full allow
+
+log_must eval "zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv1_datastream.$$"
+log_must eval "zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv1raw_datastream.$$"
+
+# create raw delegation
+log_must zfs allow $OTHER1 send:raw $TESTPOOL/$TESTFS1
+log_must zfs unallow $OTHER1 send $TESTPOOL/$TESTFS1
+
+# test new send abilities (should pass)
+log_must eval "zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv2_datastream.$$"
+log_must eval "zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv2raw_datastream.$$"
+
+
+# disable raw delegation
+zfs unallow $OTHER1 send:raw $TESTPOOL/$TESTFS1
+zfs allow $OTHER1 send $TESTPOOL/$TESTFS1
+
+# verify original send abilities (should pass)
+log_must eval "zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv3_datastream.$$"
+log_must eval "zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive $TESTPOOL/$TESTFS2/zfsrecv3raw_datastream.$$"
+
+
+function cleanup
+{
+ datasetexists $TESTPOOL/$TESTFS1 && \
+ destroy_dataset $TESTPOOL/$TESTFS1 -r \
+ destroy_dataset $TESTPOOL/$TESTFS2 -r
+
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/library.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/library.kshlib
index 0f5f6198daf2..0d07b1fd1952 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/library.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/library.kshlib
@@ -33,13 +33,16 @@
# Test one:
#
# 1. Create pool on a loopback device with some test data
-# 2. Export the pool.
-# 3. Corrupt all label checksums in the pool
-# 4. Check that pool cannot be imported
-# 5. Verify that it cannot be imported after using zhack label repair -u
+# 2. Checksum repair should work with a valid TXG. Repeatedly write and
+# sync the pool so there are enough transactions for every uberblock
+# to have a TXG
+# 3. Export the pool.
+# 4. Corrupt all label checksums in the pool
+# 5. Check that pool cannot be imported
+# 6. Verify that it cannot be imported after using zhack label repair -u
# to ensure that the -u option will quit on corrupted checksums.
-# 6. Use zhack label repair -c on device
-# 7. Check that pool can be imported and that data is intact
+# 7. Use zhack label repair -c on device
+# 8. Check that pool can be imported and that data is intact
#
# Test two:
#
@@ -97,7 +100,7 @@ VIRTUAL_MIRROR_DEVICE=
function cleanup_lo
{
- L_DEVICE="$1"
+ typeset L_DEVICE="$1"
if [[ -e $L_DEVICE ]]; then
if is_linux; then
@@ -133,9 +136,9 @@ function get_devsize
function pick_logop
{
- L_SHOULD_SUCCEED="$1"
+ typeset L_SHOULD_SUCCEED="$1"
- l_logop="log_mustnot"
+ typeset l_logop="log_mustnot"
if [ "$L_SHOULD_SUCCEED" == true ]; then
l_logop="log_must"
fi
@@ -145,7 +148,9 @@ function pick_logop
function check_dataset
{
- L_SHOULD_SUCCEED="$1"
+ typeset L_SHOULD_SUCCEED="$1"
+
+ typeset L_LOGOP=
L_LOGOP="$(pick_logop "$L_SHOULD_SUCCEED")"
"$L_LOGOP" mounted "$TESTPOOL"/"$TESTFS"
@@ -170,9 +175,21 @@ function setup_dataset
check_dataset true
}
+function force_transactions
+{
+ typeset L_TIMES="$1"
+ typeset i=
+ for ((i=0; i < L_TIMES; i++))
+ do
+ touch "$TESTDIR"/"test" || return $?
+ zpool sync -f "$TESTPOOL" || return $?
+ done
+ return 0
+}
+
function get_practical_size
{
- L_SIZE="$1"
+ typeset L_SIZE="$1"
if [ "$((L_SIZE % LABEL_SIZE))" -ne 0 ]; then
echo "$(((L_SIZE / LABEL_SIZE) * LABEL_SIZE))"
@@ -183,10 +200,11 @@ function get_practical_size
function corrupt_sized_label_checksum
{
- L_SIZE="$1"
- L_LABEL="$2"
- L_DEVICE="$3"
+ typeset L_SIZE="$1"
+ typeset L_LABEL="$2"
+ typeset L_DEVICE="$3"
+ typeset L_PRACTICAL_SIZE=
L_PRACTICAL_SIZE="$(get_practical_size "$L_SIZE")"
typeset -a L_OFFSETS=("$LABEL_CKSUM_START" \
@@ -201,8 +219,8 @@ function corrupt_sized_label_checksum
function corrupt_labels
{
- L_SIZE="$1"
- L_DISK="$2"
+ typeset L_SIZE="$1"
+ typeset L_DISK="$2"
corrupt_sized_label_checksum "$L_SIZE" 0 "$L_DISK"
corrupt_sized_label_checksum "$L_SIZE" 1 "$L_DISK"
@@ -212,11 +230,14 @@ function corrupt_labels
function try_import_and_repair
{
- L_REPAIR_SHOULD_SUCCEED="$1"
- L_IMPORT_SHOULD_SUCCEED="$2"
- L_OP="$3"
- L_POOLDISK="$4"
+ typeset L_REPAIR_SHOULD_SUCCEED="$1"
+ typeset L_IMPORT_SHOULD_SUCCEED="$2"
+ typeset L_OP="$3"
+ typeset L_POOLDISK="$4"
+
+ typeset L_REPAIR_LOGOP=
L_REPAIR_LOGOP="$(pick_logop "$L_REPAIR_SHOULD_SUCCEED")"
+ typeset L_IMPORT_LOGOP=
L_IMPORT_LOGOP="$(pick_logop "$L_IMPORT_SHOULD_SUCCEED")"
log_mustnot zpool import "$TESTPOOL" -d "$L_POOLDISK"
@@ -230,10 +251,10 @@ function try_import_and_repair
function prepare_vdev
{
- L_SIZE="$1"
- L_BACKFILE="$2"
+ typeset L_SIZE="$1"
+ typeset L_BACKFILE="$2"
- l_devname=
+ typeset l_devname=
if truncate -s "$L_SIZE" "$L_BACKFILE"; then
if is_linux; then
l_devname="$(losetup -f "$L_BACKFILE" --show)"
@@ -248,7 +269,7 @@ function prepare_vdev
function run_test_one
{
- L_SIZE="$1"
+ typeset L_SIZE="$1"
VIRTUAL_DEVICE="$(prepare_vdev "$L_SIZE" "$VIRTUAL_DISK")"
log_must test -e "$VIRTUAL_DEVICE"
@@ -257,6 +278,9 @@ function run_test_one
setup_dataset
+ # Force 256 extra transactions to ensure all uberblocks are assigned a TXG
+ log_must force_transactions 256
+
log_must zpool export "$TESTPOOL"
corrupt_labels "$L_SIZE" "$VIRTUAL_DISK"
@@ -272,7 +296,7 @@ function run_test_one
function make_mirrored_pool
{
- L_SIZE="$1"
+ typeset L_SIZE="$1"
VIRTUAL_DEVICE="$(prepare_vdev "$L_SIZE" "$VIRTUAL_DISK")"
log_must test -e "$VIRTUAL_DEVICE"
@@ -296,7 +320,7 @@ function export_and_cleanup_vdisk
function run_test_two
{
- L_SIZE="$1"
+ typeset L_SIZE="$1"
make_mirrored_pool "$L_SIZE"
@@ -317,7 +341,7 @@ function run_test_two
function run_test_three
{
- L_SIZE="$1"
+ typeset L_SIZE="$1"
make_mirrored_pool "$L_SIZE"
@@ -342,7 +366,7 @@ function run_test_three
function run_test_four
{
- L_SIZE="$1"
+ typeset L_SIZE="$1"
make_mirrored_pool "$L_SIZE"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_label_repair_001.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_label_repair_001.ksh
index ce159b555d20..b5b24322f882 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_label_repair_001.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_label_repair_001.ksh
@@ -18,13 +18,16 @@
# Strategy:
#
# 1. Create pool on a loopback device with some test data
-# 2. Export the pool.
-# 3. Corrupt all label checksums in the pool
-# 4. Check that pool cannot be imported
-# 5. Verify that it cannot be imported after using zhack label repair -u
+# 2. Checksum repair should work with a valid TXG. Repeatedly write and
+# sync the pool so there are enough transactions for every uberblock
+# to have a TXG
+# 3. Export the pool.
+# 4. Corrupt all label checksums in the pool
+# 5. Check that pool cannot be imported
+# 6. Verify that it cannot be imported after using zhack label repair -u
# to ensure that the -u option will quit on corrupted checksums.
-# 6. Use zhack label repair -c on device
-# 7. Check that pool can be imported and that data is intact
+# 7. Use zhack label repair -c on device
+# 8. Check that pool can be imported and that data is intact
. "$STF_SUITE"/tests/functional/cli_root/zhack/library.kshlib
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_metaslab_leak.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_metaslab_leak.ksh
new file mode 100755
index 000000000000..0d2a39be6b5a
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zhack/zhack_metaslab_leak.ksh
@@ -0,0 +1,70 @@
+#!/bin/ksh
+# SPDX-License-Identifier: CDDL-1.0
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+
+#
+# Description:
+#
+# Test whether zhack metaslab leak functions correctly
+#
+# Strategy:
+#
+# 1. Create pool on a loopback device with some test data
+# 2. Gather pool capacity stats
+# 3. Generate fragmentation data with zdb
+# 4. Destroy the pool
+# 5. Create a new pool with the same configuration
+# 6. Export the pool
+# 7. Apply the fragmentation information with zhack metaslab leak
+# 8. Import the pool
+# 9. Verify that pool capacity stats match
+
+. "$STF_SUITE"/include/libtest.shlib
+
+verify_runnable "global"
+
+function cleanup
+{
+ zpool destroy $TESTPOOL
+ rm $tmp
+}
+
+log_onexit cleanup
+log_assert "zhack metaslab leak leaks the right amount of space"
+
+typeset tmp=$(mktemp)
+
+log_must zpool create $TESTPOOL $DISKS
+for i in `seq 1 16`; do
+ log_must dd if=/dev/urandom of=/$TESTPOOL/f$i bs=1M count=16
+ log_must zpool sync $TESTPOOL
+done
+for i in `seq 2 2 16`; do
+ log_must rm /$TESTPOOL/f$i
+done
+for i in `seq 1 16`; do
+ log_must touch /$TESTPOOL/g$i
+ log_must zpool sync $TESTPOOL
+done
+
+alloc=$(zpool get -Hpo value alloc $TESTPOOL)
+log_must eval "zdb -m --allocated-map $TESTPOOL > $tmp"
+log_must zpool destroy $TESTPOOL
+
+log_must zpool create $TESTPOOL $DISKS
+log_must zpool export $TESTPOOL
+log_must eval "zhack metaslab leak $TESTPOOL < $tmp"
+log_must zpool import $TESTPOOL
+
+alloc2=$(zpool get -Hpo value alloc $TESTPOOL)
+
+within_percent $alloc $alloc2 98 ||
+ log_fail "space usage changed too much: $alloc to $alloc2"
+
+log_pass "zhack metaslab leak behaved correctly"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
index 091d65bb4f33..74780bb02141 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
@@ -27,6 +27,7 @@
#
# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2025 by Lawrence Livermore National Security, LLC.
#
. $STF_SUITE/include/libtest.shlib
@@ -89,3 +90,44 @@ function save_dump_dev
fi
echo $dumpdev
}
+
+function zpool_create_add_setup
+{
+ typeset -i i=0
+
+ while ((i < 10)); do
+ log_must truncate -s $MINVDEVSIZE $TEST_BASE_DIR/vdev$i
+
+ eval vdev$i=$TEST_BASE_DIR/vdev$i
+ ((i += 1))
+ done
+
+ if is_linux; then
+ vdev_lo="$(losetup -f "$vdev4" --show)"
+ elif is_freebsd; then
+ vdev_lo=/dev/"$(mdconfig -a -t vnode -f "$vdev4")"
+ else
+ vdev_lo="$(lofiadm -a "$vdev4")"
+ fi
+}
+
+function zpool_create_add_cleanup
+{
+ datasetexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+ if [[ -e $vdev_lo ]]; then
+ if is_linux; then
+ log_must losetup -d "$vdev_lo"
+ elif is_freebsd; then
+ log_must mdconfig -d -u "$vdev_lo"
+ else
+ log_must lofiadm -d "$vdev_lo"
+ fi
+ fi
+
+ typeset -i i=0
+ while ((i < 10)); do
+ rm -f $TEST_BASE_DIR/vdev$i
+ ((i += 1))
+ done
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_010_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_create.ksh
index df085a2ec746..661e55998d8d 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_010_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_create.ksh
@@ -23,67 +23,51 @@
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2025 by Lawrence Livermore National Security, LLC.
#
. $STF_SUITE/include/libtest.shlib
-. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
#
# DESCRIPTION:
-# Verify zpool add succeed when adding vdevs with matching redundancy.
+# Verify zpool add succeeds when adding vdevs with matching redundancy
+# and warns with differing redundancy for a healthy pool.
#
# STRATEGY:
# 1. Create several files == $MINVDEVSIZE.
# 2. Verify 'zpool add' succeeds with matching redundancy.
# 3. Verify 'zpool add' warns with differing redundancy.
-# 4. Verify 'zpool add' warns with differing redundancy after removal.
#
verify_runnable "global"
-function cleanup
-{
- datasetexists $TESTPOOL1 && destroy_pool $TESTPOOL1
-
- typeset -i i=0
- while ((i < 10)); do
- rm -f $TEST_BASE_DIR/vdev$i
- ((i += 1))
- done
-}
-
+log_assert "Verify 'zpool add' warns for differing redundancy."
+log_onexit zpool_create_add_cleanup
-log_assert "Verify 'zpool add' succeed with keywords combination."
-log_onexit cleanup
+zpool_create_add_setup
-# 1. Create several files == $MINVDEVSIZE.
typeset -i i=0
-while ((i < 10)); do
- log_must truncate -s $MINVDEVSIZE $TEST_BASE_DIR/vdev$i
-
- eval vdev$i=$TEST_BASE_DIR/vdev$i
- ((i += 1))
-done
+typeset -i j=0
set -A redundancy0_create_args \
"$vdev0"
set -A redundancy1_create_args \
"mirror $vdev0 $vdev1" \
- "raidz1 $vdev0 $vdev1"
+ "raidz1 $vdev0 $vdev1" \
+ "draid1:1s $vdev0 $vdev1 $vdev9"
set -A redundancy2_create_args \
"mirror $vdev0 $vdev1 $vdev2" \
- "raidz2 $vdev0 $vdev1 $vdev2"
+ "raidz2 $vdev0 $vdev1 $vdev2" \
+ "draid2:1s $vdev0 $vdev1 $vdev2 $vdev9"
set -A redundancy3_create_args \
"mirror $vdev0 $vdev1 $vdev2 $vdev3" \
- "raidz3 $vdev0 $vdev1 $vdev2 $vdev3"
+ "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" \
+ "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9"
set -A redundancy0_add_args \
"$vdev5" \
@@ -93,21 +77,19 @@ set -A redundancy1_add_args \
"mirror $vdev5 $vdev6" \
"raidz1 $vdev5 $vdev6" \
"raidz1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \
- "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8"
+ "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" \
+ "draid1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \
+ "mirror $vdev5 $vdev6 draid1 $vdev7 $vdev8"
set -A redundancy2_add_args \
"mirror $vdev5 $vdev6 $vdev7" \
- "raidz2 $vdev5 $vdev6 $vdev7"
+ "raidz2 $vdev5 $vdev6 $vdev7" \
+ "draid2 $vdev5 $vdev6 $vdev7"
set -A redundancy3_add_args \
"mirror $vdev5 $vdev6 $vdev7 $vdev8" \
- "raidz3 $vdev5 $vdev6 $vdev7 $vdev8"
-
-set -A log_args "log" "$vdev4"
-set -A cache_args "cache" "$vdev4"
-set -A spare_args "spare" "$vdev4"
-
-typeset -i j=0
+ "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" \
+ "draid3 $vdev5 $vdev6 $vdev7 $vdev8"
function zpool_create_add
{
@@ -148,30 +130,6 @@ function zpool_create_forced_add
done
}
-function zpool_create_rm_add
-{
- typeset -n create_args=$1
- typeset -n add_args=$2
- typeset -n rm_args=$3
-
- i=0
- while ((i < ${#create_args[@]})); do
- j=0
- while ((j < ${#add_args[@]})); do
- log_must zpool create $TESTPOOL1 ${create_args[$i]}
- log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]}
- log_must zpool add $TESTPOOL1 ${add_args[$j]}
- log_must zpool remove $TESTPOOL1 ${rm_args[1]}
- log_mustnot zpool add $TESTPOOL1 ${rm_args[1]}
- log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]}
- log_must zpool destroy -f $TESTPOOL1
-
- ((j += 1))
- done
- ((i += 1))
- done
-}
-
# 2. Verify 'zpool add' succeeds with matching redundancy.
zpool_create_add redundancy0_create_args redundancy0_add_args
zpool_create_add redundancy1_create_args redundancy1_add_args
@@ -195,17 +153,4 @@ zpool_create_forced_add redundancy3_create_args redundancy0_add_args
zpool_create_forced_add redundancy3_create_args redundancy1_add_args
zpool_create_forced_add redundancy3_create_args redundancy2_add_args
-# 4. Verify 'zpool add' warns with differing redundancy after removal.
-zpool_create_rm_add redundancy1_create_args redundancy1_add_args log_args
-zpool_create_rm_add redundancy2_create_args redundancy2_add_args log_args
-zpool_create_rm_add redundancy3_create_args redundancy3_add_args log_args
-
-zpool_create_rm_add redundancy1_create_args redundancy1_add_args cache_args
-zpool_create_rm_add redundancy2_create_args redundancy2_add_args cache_args
-zpool_create_rm_add redundancy3_create_args redundancy3_add_args cache_args
-
-zpool_create_rm_add redundancy1_create_args redundancy1_add_args spare_args
-zpool_create_rm_add redundancy2_create_args redundancy2_add_args spare_args
-zpool_create_rm_add redundancy3_create_args redundancy3_add_args spare_args
-
-log_pass "'zpool add' succeed with keywords combination."
+log_pass "Verify 'zpool add' warns for differing redundancy."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh
new file mode 100755
index 000000000000..313eb3666f27
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_degraded.ksh
@@ -0,0 +1,204 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2025 by Lawrence Livermore National Security, LLC.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+# Verify zpool add succeeds when adding vdevs with matching redundancy
+# and warns with differing redundancy for a degraded pool.
+#
+# STRATEGY:
+# 1. Create several files == $MINVDEVSIZE.
+# 2. Verify 'zpool add' succeeds with matching redundancy
+# 3. Verify 'zpool add' warns with differing redundancy when
+# a. Degraded pool with replaced mismatch vdev (file vs disk)
+# b. Degraded pool dRAID distributed spare active
+# c. Degraded pool hot spare active
+#
+
+verify_runnable "global"
+
+log_assert "Verify 'zpool add' warns for differing redundancy."
+log_onexit zpool_create_add_cleanup
+
+zpool_create_add_setup
+
+set -A redundancy1_create_args \
+ "mirror $vdev0 $vdev1" \
+ "raidz1 $vdev0 $vdev1" \
+ "draid1:1s $vdev0 $vdev1 $vdev9"
+
+set -A redundancy2_create_args \
+ "mirror $vdev0 $vdev1 $vdev2" \
+ "raidz2 $vdev0 $vdev1 $vdev2" \
+ "draid2:1s $vdev0 $vdev1 $vdev2 $vdev9"
+
+set -A redundancy3_create_args \
+ "mirror $vdev0 $vdev1 $vdev2 $vdev3" \
+ "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" \
+ "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9"
+
+set -A redundancy1_add_args \
+ "mirror $vdev5 $vdev6" \
+ "raidz1 $vdev5 $vdev6" \
+ "raidz1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \
+ "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" \
+ "draid1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \
+ "mirror $vdev5 $vdev6 draid1 $vdev7 $vdev8"
+
+set -A redundancy2_add_args \
+ "mirror $vdev5 $vdev6 $vdev7" \
+ "raidz2 $vdev5 $vdev6 $vdev7" \
+ "draid2 $vdev5 $vdev6 $vdev7"
+
+set -A redundancy3_add_args \
+ "mirror $vdev5 $vdev6 $vdev7 $vdev8" \
+ "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" \
+ "draid3 $vdev5 $vdev6 $vdev7 $vdev8"
+
+set -A redundancy1_create_draid_args \
+ "draid1:1s $vdev0 $vdev1 $vdev2"
+
+set -A redundancy2_create_draid_args \
+ "draid2:1s $vdev0 $vdev1 $vdev2 $vdev3"
+
+set -A redundancy3_create_draid_args \
+ "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9"
+
+set -A redundancy1_create_spare_args \
+ "mirror $vdev0 $vdev1 spare $vdev_lo" \
+ "raidz1 $vdev0 $vdev1 spare $vdev_lo" \
+ "draid1 $vdev0 $vdev1 spare $vdev_lo"
+
+set -A redundancy2_create_spare_args \
+ "mirror $vdev0 $vdev1 $vdev2 spare $vdev_lo" \
+ "raidz2 $vdev0 $vdev1 $vdev2 spare $vdev_lo" \
+ "draid2 $vdev0 $vdev1 $vdev2 spare $vdev_lo"
+
+set -A redundancy3_create_spare_args \
+ "mirror $vdev0 $vdev1 $vdev2 $vdev3 spare $vdev_lo" \
+ "raidz3 $vdev0 $vdev1 $vdev2 $vdev3 spare $vdev_lo" \
+ "draid3 $vdev0 $vdev1 $vdev2 $vdev3 spare $vdev_lo"
+
+set -A replace_args "$vdev1" "$vdev_lo"
+set -A draid1_args "$vdev1" "draid1-0-0"
+set -A draid2_args "$vdev1" "draid2-0-0"
+set -A draid3_args "$vdev1" "draid3-0-0"
+
+typeset -i i=0
+typeset -i j=0
+
+function zpool_create_degraded_add
+{
+ typeset -n create_args=$1
+ typeset -n add_args=$2
+ typeset -n rm_args=$3
+
+ i=0
+ while ((i < ${#create_args[@]})); do
+ j=0
+ while ((j < ${#add_args[@]})); do
+ log_must zpool create $TESTPOOL1 ${create_args[$i]}
+ log_must zpool offline -f $TESTPOOL1 ${rm_args[0]}
+ log_must zpool replace -w $TESTPOOL1 ${rm_args[0]} ${rm_args[1]}
+ log_must zpool add $TESTPOOL1 ${add_args[$j]}
+ log_must zpool destroy -f $TESTPOOL1
+ log_must zpool labelclear -f ${rm_args[0]}
+
+ ((j += 1))
+ done
+ ((i += 1))
+ done
+}
+
+function zpool_create_forced_degraded_add
+{
+ typeset -n create_args=$1
+ typeset -n add_args=$2
+ typeset -n rm_args=$3
+
+ i=0
+ while ((i < ${#create_args[@]})); do
+ j=0
+ while ((j < ${#add_args[@]})); do
+ log_must zpool create $TESTPOOL1 ${create_args[$i]}
+ log_must zpool offline -f $TESTPOOL1 ${rm_args[0]}
+ log_must zpool replace -w $TESTPOOL1 ${rm_args[0]} ${rm_args[1]}
+ log_mustnot zpool add $TESTPOOL1 ${add_args[$j]}
+ log_must zpool add --allow-replication-mismatch $TESTPOOL1 ${add_args[$j]}
+ log_must zpool destroy -f $TESTPOOL1
+ log_must zpool labelclear -f ${rm_args[0]}
+
+ ((j += 1))
+ done
+ ((i += 1))
+ done
+}
+
+# 2. Verify 'zpool add' succeeds with matching redundancy and a degraded pool.
+zpool_create_degraded_add redundancy1_create_args redundancy1_add_args replace_args
+zpool_create_degraded_add redundancy2_create_args redundancy2_add_args replace_args
+zpool_create_degraded_add redundancy3_create_args redundancy3_add_args replace_args
+
+# 3. Verify 'zpool add' warns with differing redundancy and a degraded pool.
+#
+# a. Degraded pool with replaced mismatch vdev (file vs disk)
+zpool_create_forced_degraded_add redundancy1_create_args redundancy2_add_args replace_args
+zpool_create_forced_degraded_add redundancy1_create_args redundancy3_add_args replace_args
+
+zpool_create_forced_degraded_add redundancy2_create_args redundancy1_add_args replace_args
+zpool_create_forced_degraded_add redundancy2_create_args redundancy3_add_args replace_args
+
+zpool_create_forced_degraded_add redundancy3_create_args redundancy1_add_args replace_args
+zpool_create_forced_degraded_add redundancy3_create_args redundancy2_add_args replace_args
+
+# b. Degraded pool dRAID distributed spare active
+
+zpool_create_forced_degraded_add redundancy1_create_draid_args redundancy2_add_args draid1_args
+zpool_create_forced_degraded_add redundancy1_create_draid_args redundancy3_add_args draid1_args
+
+zpool_create_forced_degraded_add redundancy2_create_draid_args redundancy1_add_args draid2_args
+zpool_create_forced_degraded_add redundancy2_create_draid_args redundancy3_add_args draid2_args
+
+zpool_create_forced_degraded_add redundancy3_create_draid_args redundancy1_add_args draid3_args
+zpool_create_forced_degraded_add redundancy3_create_draid_args redundancy2_add_args draid3_args
+
+# c. Degraded pool hot spare active
+zpool_create_forced_degraded_add redundancy1_create_spare_args redundancy2_add_args replace_args
+zpool_create_forced_degraded_add redundancy1_create_spare_args redundancy3_add_args replace_args
+
+zpool_create_forced_degraded_add redundancy2_create_spare_args redundancy1_add_args replace_args
+zpool_create_forced_degraded_add redundancy2_create_spare_args redundancy3_add_args replace_args
+
+zpool_create_forced_degraded_add redundancy3_create_spare_args redundancy1_add_args replace_args
+zpool_create_forced_degraded_add redundancy3_create_spare_args redundancy2_add_args replace_args
+
+log_pass "Verify 'zpool add' warns for differing redundancy."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh
new file mode 100755
index 000000000000..782858e301ac
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_warn_removal.ksh
@@ -0,0 +1,126 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2012, 2016 by Delphix. All rights reserved.
+# Copyright 2025 by Lawrence Livermore National Security, LLC.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+# Verify zpool add succeeds when adding vdevs with matching redundancy
+# and warns with differing redundancy after removal.
+#
+# STRATEGY:
+# 1. Create several files == $MINVDEVSIZE.
+# 2. Verify 'zpool add' warns with differing redundancy after removal.
+#
+
+verify_runnable "global"
+
+log_assert "Verify 'zpool add' warns for differing redundancy."
+log_onexit zpool_create_add_cleanup
+
+zpool_create_add_setup
+
+typeset -i i=0
+typeset -i j=0
+
+set -A redundancy1_create_args \
+ "mirror $vdev0 $vdev1" \
+ "raidz1 $vdev0 $vdev1" \
+ "draid1:1s $vdev0 $vdev1 $vdev9"
+
+set -A redundancy2_create_args \
+ "mirror $vdev0 $vdev1 $vdev2" \
+ "raidz2 $vdev0 $vdev1 $vdev2" \
+ "draid2:1s $vdev0 $vdev1 $vdev2 $vdev9"
+
+set -A redundancy3_create_args \
+ "mirror $vdev0 $vdev1 $vdev2 $vdev3" \
+ "raidz3 $vdev0 $vdev1 $vdev2 $vdev3" \
+ "draid3:1s $vdev0 $vdev1 $vdev2 $vdev3 $vdev9"
+
+set -A redundancy1_add_args \
+ "mirror $vdev5 $vdev6" \
+ "raidz1 $vdev5 $vdev6" \
+ "raidz1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \
+ "mirror $vdev5 $vdev6 raidz1 $vdev7 $vdev8" \
+ "draid1 $vdev5 $vdev6 mirror $vdev7 $vdev8" \
+ "mirror $vdev5 $vdev6 draid1 $vdev7 $vdev8"
+
+set -A redundancy2_add_args \
+ "mirror $vdev5 $vdev6 $vdev7" \
+ "raidz2 $vdev5 $vdev6 $vdev7" \
+ "draid2 $vdev5 $vdev6 $vdev7"
+
+set -A redundancy3_add_args \
+ "mirror $vdev5 $vdev6 $vdev7 $vdev8" \
+ "raidz3 $vdev5 $vdev6 $vdev7 $vdev8" \
+ "draid3 $vdev5 $vdev6 $vdev7 $vdev8"
+
+set -A log_args "log" "$vdev_lo"
+set -A cache_args "cache" "$vdev_lo"
+set -A spare_args "spare" "$vdev_lo"
+
+
+function zpool_create_rm_add
+{
+ typeset -n create_args=$1
+ typeset -n add_args=$2
+ typeset -n rm_args=$3
+
+ i=0
+ while ((i < ${#create_args[@]})); do
+ j=0
+ while ((j < ${#add_args[@]})); do
+ log_must zpool create $TESTPOOL1 ${create_args[$i]}
+ log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]}
+ log_must zpool add $TESTPOOL1 ${add_args[$j]}
+ log_must zpool remove $TESTPOOL1 ${rm_args[1]}
+ log_mustnot zpool add $TESTPOOL1 ${rm_args[1]}
+ log_must zpool add $TESTPOOL1 ${rm_args[0]} ${rm_args[1]}
+ log_must zpool destroy -f $TESTPOOL1
+
+ ((j += 1))
+ done
+ ((i += 1))
+ done
+}
+
+# 2. Verify 'zpool add' warns with differing redundancy after removal.
+zpool_create_rm_add redundancy1_create_args redundancy1_add_args log_args
+zpool_create_rm_add redundancy2_create_args redundancy2_add_args log_args
+zpool_create_rm_add redundancy3_create_args redundancy3_add_args log_args
+
+zpool_create_rm_add redundancy1_create_args redundancy1_add_args cache_args
+zpool_create_rm_add redundancy2_create_args redundancy2_add_args cache_args
+zpool_create_rm_add redundancy3_create_args redundancy3_add_args cache_args
+
+zpool_create_rm_add redundancy1_create_args redundancy1_add_args spare_args
+zpool_create_rm_add redundancy2_create_args redundancy2_add_args spare_args
+zpool_create_rm_add redundancy3_create_args redundancy3_add_args spare_args
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh
new file mode 100755
index 000000000000..099b5426031d
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/cleanup.ksh
@@ -0,0 +1,30 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara, Inc.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh
new file mode 100755
index 000000000000..3529a0ccc015
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/setup.ksh
@@ -0,0 +1,32 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara, Inc.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib
new file mode 100644
index 000000000000..ea4b0bd2756d
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib
@@ -0,0 +1,235 @@
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara, Inc.
+#
+
+# Since we want to make sure that iostat responds correctly as pools appear and
+# disappear, we run it in the background and capture its output to a file.
+# Once we're done, we parse the output and ensure it matches what we'd expect
+# from the operations we performed.
+#
+# Because iostat is producing output every interval, it may produce the "same"
+# output for each step of the change; in fact, we want that to make sure we
+# don't miss anything. So, we describe what we expect as a series of "chunks".
+# Each chunk is a particular kind of output, which may repeat. Current known
+# chunk types are:
+#
+# NOPOOL: the text "no pools available"
+# HEADER: three lines, starting with "capacity", "pool" and "----" respectively.
+# (the rough shape of the normal iostat header).
+# POOL1: a line starting with "pool1" (stats line for a pool of that name)
+# POOL2: a line starting with "pool2"
+# POOLBOTH: three lines, starting with "pool1", "pool2" (either order) and
+# "-----" respectively. (the pool stat output for multiple pools)
+#
+# (the parser may produce other chunks in a failed parse to assist with
+# debugging, but they should never be part of the "wanted" output See the
+# parser commentary below).
+#
+# To help recognise the start of a new interval output, we run iostat with the
+# -T u option, which will output a numeric timestamp before each header or
+# second-or-later pool stat after the header.
+#
+# To keep the test run shorter, we use a subsecond interval, but to make sure
+# nothing is missed, we sleep for three intervals after each change.
+
+typeset _iostat_out=$(mktemp)
+typeset _iostat_pid=""
+
+function cleanup_iostat {
+ if [[ -n $_iostat_pid ]] ; then
+ kill -KILL $_iostat_pid || true
+ fi
+ rm -f $_iostat_out
+}
+
+function start_iostat {
+ zpool iostat -T u $@ 0.1 > $_iostat_out 2>&1 &
+ _iostat_pid=$!
+}
+
+function stop_iostat {
+ kill -TERM $_iostat_pid
+ wait $_iostat_pid
+ _iostat_pid=""
+}
+
+function delay_iostat {
+ sleep 0.3
+}
+
+typeset -a _iostat_expect
+function expect_iostat {
+ typeset chunk=$1
+ _iostat_expect+=($chunk)
+}
+
+# Parse the output The `state` var is used to track state across
+# multiple lines. The `last` var and the `_got_iostat` function are used
+# to record the completed chunks, and to collapse repetitions.
+typeset -a _iostat_got
+typeset _iostat_last=""
+typeset _iostat_state=""
+
+function _got_iostat {
+ typeset chunk=$1
+ if [[ -n $chunk && $_iostat_last != $chunk ]] ; then
+ _iostat_last=$chunk
+ _iostat_got+=($chunk)
+ fi
+ _iostat_state=""
+}
+
+function verify_iostat {
+
+ cat $_iostat_out | while read line ; do
+
+ # The "no pools available" text has no timestamp or other
+ # header, and should never appear in the middle of multiline
+ # chunk, so we can close any in-flight state.
+ if [[ $line = "no pools available" ]] ; then
+ _got_iostat $_iostat_state
+ _got_iostat "NOPOOL"
+ continue
+ fi
+
+ # A run of digits alone on the line is a timestamp (the `-T u`
+ # switch to `iostat`). It closes any in-flight state as a
+ # complete chunk, and indicates the start of a new chunk.
+ if [[ -z ${line/#+([0-9])/} ]] ; then
+ _got_iostat $_iostat_state
+ _iostat_state="TIMESTAMP"
+ continue
+ fi
+
+ # For this test, the first word of each line should be unique,
+ # so we extract it and use it for simplicity.
+ typeset first=${line%% *}
+
+ # Header is emitted whenever the pool list changes. It has
+ # three lines:
+ #
+ # capacity operations bandwidth
+ # pool alloc free read write read write
+ # ---------- ----- ----- ----- ----- ----- -----
+ #
+ # Each line moves the state; when we get to a run of dashes, we
+ # commit. Note that we check for one-or-more dashes, because
+ # the width can vary depending on the length of pool name.
+ #
+ if [[ $_iostat_state = "TIMESTAMP" &&
+ $first = "capacity" ]] ; then
+ _iostat_state="INHEADER1"
+ continue
+ fi
+ if [[ $_iostat_state = "INHEADER1" &&
+ $first = "pool" ]] ; then
+ _iostat_state="INHEADER2"
+ continue
+ fi
+ if [[ $_iostat_state = "INHEADER2" &&
+ -z ${first/#+(-)/} ]] ; then
+ # Headers never repeat, so if the last committed chunk
+ # was a header, we commit this one as EXTRAHEADER so we
+ # can see it in the error output.
+ if [[ $_iostat_last = "HEADER" ]] ; then
+ _got_iostat "EXTRAHEADER"
+ elif [[ $_iostat_last != "EXTRAHEADER" ]] ; then
+ _got_iostat "HEADER"
+ fi
+ _iostat_state="HEADER"
+ continue
+ fi
+
+ # A pool stat line looks like:
+ #
+ # pool1 147K 240M 0 0 0 0
+ #
+ # If there are multiple pools, iostat follows them with a
+ # separator of dashed lines:
+ #
+ # pool1 147K 240M 0 0 0 0
+ # pool2 147K 240M 0 0 0 0
+ # ---------- ----- ----- ----- ----- ----- -----
+ #
+ # Stats rows always start after a timestamp or a header. If the
+ # header was emitted, we won't see a timestamp here (it goes
+ # before the header).
+ #
+ # Because our test exercises both pools on their own and
+ # together, we allow pools in either order. In practice they
+ # are sorted, but that's a side-effect of the implementation
+ # (see zpool_compare()), so we're not going to rely on it here.
+ if [[ $first = "pool1" ]] || [[ $first = "pool2" ]] ; then
+
+ # First line, track which one we saw. If it's a
+ # standalone line, it will be committed by the next
+ # NOPOOL or TIMESTAMP above (or the `_got_iostat` after
+ # the loop if this is the last line).
+ if [[ $_iostat_state == "TIMESTAMP" ||
+ $_iostat_state == "HEADER" ]] ; then
+ if [[ $first = "pool1" ]] ; then
+ _iostat_state="POOL1"
+ elif [[ $first = "pool2" ]] ; then
+ _iostat_state="POOL2"
+ fi
+ continue
+ fi
+
+ # If this is the second pool, we're in a multi-pool
+ # block, and need to look for the separator to close it
+ # out.
+ if [[ $_iostat_state = "POOL1" && $first = "pool2" ]] ||
+ [[ $_iostat_state = "POOL2" && $first = "pool1" ]] ;
+ then
+ _iostat_state="INPOOLBOTH"
+ continue
+ fi
+ fi
+
+ # Separator after the stats block.
+ if [[ $_iostat_state = "INPOOLBOTH" &&
+ -z ${first/#+(-)/} ]] ; then
+ _got_iostat "POOLBOTH"
+ continue
+ fi
+
+ # Anything else will fall through to here. We commit any
+ # in-flight state, then "UNKNOWN", all to help with debugging..
+ if [[ $_iostat_state != "UNKNOWN" ]] ; then
+ _got_iostat $_iostat_state
+ _got_iostat "UNKNOWN"
+ fi
+ done
+
+ # Close out any remaining state.
+ _got_iostat $_iostat_state
+
+ # Compare what we wanted with what we got, and pass/fail the test!
+ if [[ "${_iostat_expect[*]}" != "${_iostat_got[*]}" ]] ; then
+ log_note "expected: ${_iostat_expect[*]}"
+ log_note " got: ${_iostat_got[*]}"
+ log_fail "zpool iostat did not produce expected output"
+ fi
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh
new file mode 100755
index 000000000000..8e040058ec3e
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_all.ksh
@@ -0,0 +1,90 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara, Inc.
+#
+
+# `zpool iostat <N>` should keep running and update the pools it displays as
+# pools are created/destroyed/imported/export.
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib
+
+typeset vdev1=$(mktemp)
+typeset vdev2=$(mktemp)
+
+function cleanup {
+ cleanup_iostat
+
+ poolexists pool1 && destroy_pool pool1
+ poolexists pool2 && destroy_pool pool2
+ rm -f $vdev1 $vdev2
+}
+
+log_must mkfile $MINVDEVSIZE $vdev1 $vdev2
+
+expect_iostat "NOPOOL"
+
+start_iostat
+
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOL1"
+log_must zpool create pool1 $vdev1
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOLBOTH"
+log_must zpool create pool2 $vdev2
+delay_iostat
+
+expect_iostat "NOPOOL"
+log_must zpool export -a
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOL2"
+log_must zpool import -d $vdev2 pool2
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOLBOTH"
+log_must zpool import -d $vdev1 pool1
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOL2"
+log_must zpool destroy pool1
+delay_iostat
+
+expect_iostat "NOPOOL"
+log_must zpool destroy pool2
+delay_iostat
+
+stop_iostat
+
+verify_iostat
+
+log_pass "zpool iostat in interval mode follows pool updates"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh
new file mode 100755
index 000000000000..ab1f258aa1cd
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_iostat/zpool_iostat_interval_some.ksh
@@ -0,0 +1,80 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara, Inc.
+#
+
+# `zpool iostat <pools> <N>` should keep running and only show the listed pools.
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_iostat/zpool_iostat.kshlib
+
+typeset vdev1=$(mktemp)
+typeset vdev2=$(mktemp)
+
+function cleanup {
+ cleanup_iostat
+
+ poolexists pool1 && destroy_pool pool1
+ poolexists pool2 && destroy_pool pool2
+ rm -f $vdev1 $vdev2
+}
+
+log_must mkfile $MINVDEVSIZE $vdev1 $vdev2
+
+log_must zpool create pool1 $vdev1
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOL1"
+start_iostat pool1
+delay_iostat
+
+log_must zpool create pool2 $vdev2
+delay_iostat
+
+expect_iostat "NOPOOL"
+log_must zpool export -a
+delay_iostat
+
+log_must zpool import -d $vdev2 pool2
+delay_iostat
+
+expect_iostat "HEADER"
+expect_iostat "POOL1"
+log_must zpool import -d $vdev1 pool1
+delay_iostat
+
+expect_iostat "NOPOOL"
+log_must zpool destroy pool1
+delay_iostat
+
+log_must zpool destroy pool2
+delay_iostat
+
+stop_iostat
+
+verify_iostat
+
+log_pass "zpool iostat in interval mode with pools follows listed pool updates"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_date_range_002.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_date_range_002.ksh
new file mode 100755
index 000000000000..9327df81a5c5
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_date_range_002.ksh
@@ -0,0 +1,76 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2025 Klara, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
+
+#
+# DESCRIPTION:
+# Verify that the timestamp database updates all the tables as expected.
+#
+# STRATEGY:
+# 1. Decrease the note and flush frequency of the txg database.
+# 2. Force the pool to sync several txgs
+# 3. Verify that there are entries in each of the "month", "day", and
+# "minute" tables.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+ log_must restore_tunable SPA_NOTE_TXG_TIME
+ log_must restore_tunable SPA_FLUSH_TXG_TIME
+ rm /$TESTPOOL/f1
+}
+
+log_onexit cleanup
+
+log_assert "Verifiy timestamp databases all update as expected."
+
+log_must save_tunable SPA_NOTE_TXG_TIME
+log_must set_tunable64 SPA_NOTE_TXG_TIME 1
+log_must save_tunable SPA_FLUSH_TXG_TIME
+log_must set_tunable64 SPA_FLUSH_TXG_TIME 1
+
+log_must touch /$TESTPOOL/f1
+log_must zpool sync $TESTPOOL
+sleep 1
+log_must touch /$TESTPOOL/f1
+log_must zpool sync $TESTPOOL
+sleep 1
+log_must touch /$TESTPOOL/f1
+log_must zpool sync $TESTPOOL
+
+mos_zap="$(zdb -dddd $TESTPOOL 1)"
+minutes_entries=$(echo "$mos_zap" | grep "txg_log_time:minutes" | awk '{print $5}')
+days_entries=$(echo "$mos_zap" | grep "txg_log_time:days" | awk '{print $5}')
+months_entries=$(echo "$mos_zap" | grep "txg_log_time:months" | awk '{print $5}')
+
+[[ "$minutes_entries" -ne "0" ]] || log_fail "0 entries in the minutes table"
+[[ "$days_entries" -ne "0" ]] || log_fail "0 entries in the days table"
+[[ "$months_entries" -ne "0" ]] || log_fail "0 entries in the months table"
+
+log_pass "Verified all timestamp databases had entries as expected."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arcstat_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcstat_001_pos.ksh
index 700bd9a6f529..d63b72f8039d 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arcstat_001_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcstat_001_pos.ksh
@@ -37,7 +37,7 @@ log_assert "arcstat generates output and doesn't return an error code"
typeset -i i=0
while [[ $i -lt ${#args[*]} ]]; do
- log_must eval "arcstat ${args[i]} > /dev/null"
+ log_must eval "zarcstat ${args[i]} > /dev/null"
((i = i + 1))
done
log_pass "arcstat generates output and doesn't return an error code"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcsummary_001_pos.ksh
index 0840878fdb0d..b7faac5243c9 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_001_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcsummary_001_pos.ksh
@@ -30,16 +30,16 @@
is_freebsd && ! python3 -c 'import sysctl' 2>/dev/null && log_unsupported "python3 sysctl module missing"
-log_assert "arc_summary generates output and doesn't return an error code"
+log_assert "zarcsummary generates output and doesn't return an error code"
# Without this, the below checks aren't going to work the way we hope...
set -o pipefail
for arg in "" "-a" "-d" "-p 1" "-g" "-s arc" "-r"; do
- log_must eval "arc_summary $arg > /dev/null"
+ log_must eval "zarcsummary $arg > /dev/null"
done
-log_must eval "arc_summary | head > /dev/null"
-log_must eval "arc_summary | head -1 > /dev/null"
+log_must eval "zarcsummary | head > /dev/null"
+log_must eval "zarcsummary | head -1 > /dev/null"
-log_pass "arc_summary generates output and doesn't return an error code"
+log_pass "zarcsummary generates output and doesn't return an error code"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_002_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcsummary_002_neg.ksh
index ec4abe35409d..227646777ba0 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_002_neg.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/misc/zarcsummary_002_neg.ksh
@@ -30,10 +30,10 @@
is_freebsd && ! python3 -c 'import sysctl' 2>/dev/null && log_unsupported "python3 sysctl module missing"
-log_assert "arc_summary generates an error code with invalid options"
+log_assert "zarcsummary generates an error code with invalid options"
for arg in "-x" "-5" "-p 7" "--err" "-@"; do
- log_mustnot eval "arc_summary $arg > /dev/null"
+ log_mustnot eval "zarcsummary $arg > /dev/null"
done
-log_pass "arc_summary generates an error code with invalid options"
+log_pass "zarcsummary generates an error code with invalid options"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/cleanup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/cleanup.ksh
new file mode 100755
index 000000000000..4a59e15cc693
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/cleanup.ksh
@@ -0,0 +1,43 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+
+poolexists $TESTPOOL1 && \
+ destroy_pool $TESTPOOL1
+
+del_user $STAFF1
+del_user $STAFF2
+del_group $STAFF_GROUP
+
+del_user $OTHER1
+del_user $OTHER2
+del_group $OTHER_GROUP
+
+default_cleanup
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/setup.ksh
new file mode 100755
index 000000000000..0978193eddc4
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/setup.ksh
@@ -0,0 +1,50 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+# Create staff group and add two user to it
+log_must add_group $STAFF_GROUP
+if ! id $STAFF1 > /dev/null 2>&1; then
+ log_must add_user $STAFF_GROUP $STAFF1
+fi
+if ! id $STAFF2 > /dev/null 2>&1; then
+ log_must add_user $STAFF_GROUP $STAFF2
+fi
+
+# Create other group and add two user to it
+log_must add_group $OTHER_GROUP
+if ! id $OTHER1 > /dev/null 2>&1; then
+ log_must add_user $OTHER_GROUP $OTHER1
+fi
+if ! id $OTHER2 > /dev/null 2>&1; then
+ log_must add_user $OTHER_GROUP $OTHER2
+fi
+DISK=${DISKS%% *}
+
+default_raidz_setup $DISKS
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/zfs_send_usertest.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/zfs_send_usertest.ksh
new file mode 100755
index 000000000000..f62f2b07929c
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_user/zfs_send_delegation_user/zfs_send_usertest.ksh
@@ -0,0 +1,145 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025, Klara Inc.
+#
+
+# STRATEGY:
+# 1. Create a pool (this is done by the test framework)
+# 2. Create a user
+# 3. Create an encrypted dataset
+# 4. Write random data to the encrypted dataset
+# 5. Snapshot the dataset
+# 6. As root: attempt a send and raw send (both should succeed)
+# 7. As user: attempt a send and raw send (both should fail, no permission)
+# 8. Create a delegation (zfs allow -u user send testpool/encrypted_dataset)
+# 9. As root: attempt a send and raw send (both should succeed)
+# 10. As user: attempt a send and raw send (both should succeed)
+# 11. Create a delegation (zfs allow -u user sendraw testpool/encrypted_dataset)
+# 12. As root: attempt a send and raw send (both should succeed)
+# 13. As user: attempt a send and raw send (send should fail, raw send should succeed)
+# 14. Disable delegation (zfs unallow)
+# 15. As root: attempt a send and raw send (both should succeed)
+# 16. As user: attempt a send and raw send (both should fail, no permission)
+# 17. Clean up (handled by framework)
+# root tests to verify this doesnt affect root user under ../cli_root/zfs_send_delegation/
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib
+. $STF_SUITE/tests/functional/delegate/delegate.cfg
+
+# create encrypted dataset
+
+log_must eval "echo $PASSPHRASE | zfs create -o encryption=on -o keyformat=passphrase $TESTPOOL/$TESTFS1"
+
+# create target dataset for receives
+log_must zfs create $TESTPOOL/$TESTFS2
+
+# set user perms
+# need to run chown for fs permissions for $OTHER1
+typeset perms="snapshot,reservation,compression,checksum,userprop,receive,mount,create"
+
+log_must zfs allow $OTHER1 $perms $TESTPOOL/$TESTFS1
+log_must zfs allow $OTHER1 $perms $TESTPOOL/$TESTFS2
+log_must chown ${OTHER1}:${OTHER_GROUP} /$TESTPOOL/$TESTFS2
+
+# create random data
+log_must fill_fs $TESTPOOL/$TESTFS1/child 1 2047 1024 1 R
+
+# snapshot
+log_must zfs snapshot $TESTPOOL/$TESTFS1@snap1
+
+# note
+# we need to use `sh -c` here becuase the quoting on <<<"$*" in the user_run wrapper is broken once pipes and redirects get involved
+
+# check baseline send abilities (should fail)
+log_mustnot user_run $OTHER1 sh -c "'zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv0_user_datastream.$$'"
+# verify nothing went through
+if [ -s $TESTPOOL/$TESTFS2/zfsrecv0_user_datastream.$$ ]
+then
+ log_fail "A zfs recieve was completed in $TESTPOOL/$TESTFS2/zfsrecv0_user_datastream !"
+fi
+log_mustnot user_run $OTHER1 sh -c "'zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv0raw_user_datastream.$$'"
+# verify nothing went through
+if [ -s $TESTPOOL/$TESTFS2/zfsrecv0raw_user_datastream.$$ ]
+then
+ log_fail "A zfs recieve was completed in $TESTPOOL/$TESTFS2/zfsrecv0raw_user_datastream !"
+fi
+
+# create delegation
+log_must zfs allow $OTHER1 send $TESTPOOL/$TESTFS1
+
+# attempt send with full allow (should pass)
+log_must user_run $OTHER1 sh -c "'zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv1_user_datastream.$$'"
+log_must user_run $OTHER1 sh -c "'zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv1raw_user_datastream.$$'"
+
+
+# create raw delegation
+log_must zfs allow $OTHER1 send:raw $TESTPOOL/$TESTFS1
+# We have to remove 'send' to confirm 'send raw' only allows what we want
+log_must zfs unallow -u $OTHER1 send $TESTPOOL/$TESTFS1
+
+# test new sendraw abilities (send should fail, sendraw should pass)
+log_mustnot user_run $OTHER1 sh -c "'zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv2_user_datastream.$$'"
+ verify nothing went through
+if [ -s $TESTPOOL/$TESTFS2/zfsrecv2_user_datastream.$$ ]
+then
+ log_fail "A zfs recieve was completed in $TESTPOOL/$TESTFS2/zfsrecv2_user_datastream !"
+fi
+log_must user_run $OTHER1 sh -c "'zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv2raw_user_datastream.$$'"
+
+# disable raw delegation
+log_must zfs unallow -u $OTHER1 send:raw $TESTPOOL/$TESTFS1
+log_must zfs allow $OTHER1 send $TESTPOOL/$TESTFS1
+
+# test with raw taken away (should pass)
+log_must user_run $OTHER1 sh -c "'zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv3_user_datastream.$$'"
+log_must user_run $OTHER1 sh -c "'zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv3raw_user_datastream.$$'"
+
+# disable send abilities
+log_must zfs unallow -u $OTHER1 send $TESTPOOL/$TESTFS1
+
+# verify original send abilities (should fail)
+log_mustnot user_run $OTHER1 sh -c "'zfs send $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv4_user_datastream.$$'"
+ verify nothing went through
+if [ -s $TESTPOOL/$TESTFS2/zfsrecv4_user_datastream.$$ ]
+then
+ log_fail "A zfs recieve was completed in $TESTPOOL/$TESTFS2/zfsrecv4_user_datastream !"
+fi
+log_mustnot user_run $OTHER1 sh -c "'zfs send -w $TESTPOOL/$TESTFS1@snap1 | zfs receive -u $TESTPOOL/$TESTFS2/zfsrecv4raw_user_datastream.$$'"
+ verify nothing went through
+if [ -s $TESTPOOL/$TESTFS2/zfsrecv4raw_user_datastream.$$ ]
+then
+ log_fail "A zfs recieve was completed in $TESTPOOL/$TESTFS2/zfsrecv4raw_user_datastream !"
+fi
+
+
+function cleanup
+{
+ datasetexists $TESTPOOL/$TESTFS1 && \
+ destroy_dataset $TESTPOOL/$TESTFS1 -r \
+ destroy_dataset $TESTPOOL/$TESTFS2 -r
+
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib
index 0a402e71ee68..345239b88680 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib
@@ -1234,10 +1234,10 @@ function verify_fs_aedsx
typeset oldval
set -A modes "on" "off"
oldval=$(get_prop $perm $fs)
- if [[ $oldval == "on" ]]; then
- n=1
- elif [[ $oldval == "off" ]]; then
+ if [[ $oldval == "off" ]]; then
n=0
+ else
+ n=1
fi
log_note "$user zfs set $perm=${modes[$n]} $fs"
user_run $user zfs set $perm=${modes[$n]} $fs
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_degraded_sit_out.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_degraded_sit_out.ksh
new file mode 100755
index 000000000000..d5feb6936b4b
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_degraded_sit_out.ksh
@@ -0,0 +1,106 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
+# Copyright (c) 2025 by Klara, Inc.
+
+# DESCRIPTION:
+# Verify that vdevs 'sit out' when they are slow
+#
+# STRATEGY:
+# 1. Create various raidz/draid pools
+# 2. Degrade/fault one of the disks.
+# 3. Inject delays into one of the disks
+# 4. Verify disk is set to 'sit out' for awhile.
+# 5. Wait for READ_SIT_OUT_SECS and verify sit out state is lifted.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+ restore_tunable READ_SIT_OUT_SECS
+ restore_tunable SIT_OUT_CHECK_INTERVAL
+ log_must zinject -c all
+ log_must zpool events -c
+ destroy_pool $TESTPOOL2
+ log_must rm -f $TEST_BASE_DIR/vdev.$$.*
+}
+
+log_assert "Verify sit_out works"
+
+log_onexit cleanup
+
+# shorten sit out period for testing
+save_tunable READ_SIT_OUT_SECS
+set_tunable32 READ_SIT_OUT_SECS 5
+
+save_tunable SIT_OUT_CHECK_INTERVAL
+set_tunable64 SIT_OUT_CHECK_INTERVAL 20
+
+log_must truncate -s 150M $TEST_BASE_DIR/vdev.$$.{0..9}
+
+for raidtype in raidz2 raidz3 draid2 draid3 ; do
+ log_must zpool create $TESTPOOL2 $raidtype $TEST_BASE_DIR/vdev.$$.{0..9}
+ log_must zpool set autosit=on $TESTPOOL2 "${raidtype}-0"
+ log_must dd if=/dev/urandom of=/$TESTPOOL2/bigfile bs=1M count=400
+ log_must zpool export $TESTPOOL2
+ log_must zpool import -d $TEST_BASE_DIR $TESTPOOL2
+
+ BAD_VDEV=$TEST_BASE_DIR/vdev.$$.9
+ SLOW_VDEV=$TEST_BASE_DIR/vdev.$$.8
+
+ # Initial state should not be sitting out
+ log_must eval [[ "$(get_vdev_prop sit_out $TESTPOOL2 $SLOW_VDEV)" == "off" ]]
+
+ # Delay our reads 200ms to trigger sit out
+ log_must zinject -d $SLOW_VDEV -D200:1 -T read $TESTPOOL2
+ type=$((RANDOM % 2))
+ [[ "$type" -eq "0" ]] && action="degrade" || action="fault"
+ log_must zinject -d $BAD_VDEV -A $action -T read $TESTPOOL2
+
+ # Do some reads and wait for us to sit out
+ for i in {0..99} ; do
+ dd if=/$TESTPOOL2/bigfile skip=$i bs=2M count=1 of=/dev/null &
+ dd if=/$TESTPOOL2/bigfile skip=$((i + 100)) bs=2M count=1 of=/dev/null
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL2 $SLOW_VDEV)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+ done
+
+ log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $SLOW_VDEV)" == "on"
+
+ # Clear fault injection
+ log_must zinject -c all
+
+ # Wait for us to exit our sit out period
+ log_must wait_sit_out $TESTPOOL2 $SLOW_VDEV 10
+
+ log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $SLOW_VDEV)" == "off"
+ destroy_pool $TESTPOOL2
+ log_must zpool labelclear -f $BAD_VDEV
+done
+
+log_pass "sit_out works correctly"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out.ksh
new file mode 100755
index 000000000000..37f616cf56ee
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out.ksh
@@ -0,0 +1,102 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
+
+# DESCRIPTION:
+# Verify that vdevs 'sit out' when they are slow
+#
+# STRATEGY:
+# 1. Create various raidz/draid pools
+# 2. Inject delays into one of the disks
+# 3. Verify disk is set to 'sit out' for awhile.
+# 4. Wait for READ_SIT_OUT_SECS and verify sit out state is lifted.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+ restore_tunable READ_SIT_OUT_SECS
+ restore_tunable SIT_OUT_CHECK_INTERVAL
+ log_must zinject -c all
+ log_must zpool events -c
+ destroy_pool $TESTPOOL2
+ log_must rm -f $TEST_BASE_DIR/vdev.$$.*
+}
+
+log_assert "Verify sit_out works"
+
+log_onexit cleanup
+
+# shorten sit out period for testing
+save_tunable READ_SIT_OUT_SECS
+set_tunable32 READ_SIT_OUT_SECS 5
+
+save_tunable SIT_OUT_CHECK_INTERVAL
+set_tunable64 SIT_OUT_CHECK_INTERVAL 20
+
+log_must truncate -s200M $TEST_BASE_DIR/vdev.$$.{0..9}
+
+for raidtype in raidz raidz2 raidz3 draid1 draid2 draid3 ; do
+ log_must zpool create $TESTPOOL2 $raidtype $TEST_BASE_DIR/vdev.$$.{0..9}
+ log_must zpool set autosit=on $TESTPOOL2 "${raidtype}-0"
+ log_must dd if=/dev/urandom of=/$TESTPOOL2/bigfile bs=1M count=600
+ log_must zpool export $TESTPOOL2
+ log_must zpool import -d $TEST_BASE_DIR $TESTPOOL2
+
+ BAD_VDEV=$TEST_BASE_DIR/vdev.$$.9
+
+ # Initial state should not be sitting out
+ log_must eval [[ "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV)" == "off" ]]
+
+ # Delay our reads 200ms to trigger sit out
+ log_must zinject -d $BAD_VDEV -D200:1 -T read $TESTPOOL2
+
+ # Do some reads and wait for us to sit out
+ for i in {0..99} ; do
+ dd if=/$TESTPOOL2/bigfile skip=$i bs=2M count=1 of=/dev/null &
+ dd if=/$TESTPOOL2/bigfile skip=$((i + 100)) bs=2M count=1 of=/dev/null &
+ dd if=/$TESTPOOL2/bigfile skip=$((i + 200)) bs=2M count=1 of=/dev/null
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+ done
+
+ log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV)" == "on"
+
+ # Clear fault injection
+ log_must zinject -c all
+
+ # Wait for us to exit our sit out period
+ log_must wait_sit_out $TESTPOOL2 $BAD_VDEV 10
+
+ # Verify sit_out was cleared during wait_sit_out
+ log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV)" == "off"
+
+ destroy_pool $TESTPOOL2
+done
+
+log_pass "sit_out works correctly"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out_neg.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out_neg.ksh
new file mode 100755
index 000000000000..457105a66453
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/slow_vdev_sit_out_neg.ksh
@@ -0,0 +1,116 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
+# Copyright (c) 2025 by Klara, Inc.
+
+# DESCRIPTION:
+# Verify that we don't sit out too many vdevs
+#
+# STRATEGY:
+# 1. Create draid2 pool
+# 2. Inject delays into three of the disks
+# 3. Do reads to trigger sit-outs
+# 4. Verify exactly 2 disks sit out
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+ restore_tunable READ_SIT_OUT_SECS
+ restore_tunable SIT_OUT_CHECK_INTERVAL
+ log_must zinject -c all
+ log_must zpool events -c
+ destroy_pool $TESTPOOL2
+ log_must rm -f $TEST_BASE_DIR/vdev.$$.*
+}
+
+log_assert "Verify sit_out works"
+
+log_onexit cleanup
+
+save_tunable SIT_OUT_CHECK_INTERVAL
+set_tunable64 SIT_OUT_CHECK_INTERVAL 20
+
+log_must truncate -s 150M $TEST_BASE_DIR/vdev.$$.{0..9}
+
+log_must zpool create $TESTPOOL2 draid2 $TEST_BASE_DIR/vdev.$$.{0..9}
+log_must zpool set autosit=on $TESTPOOL2 draid2-0
+log_must dd if=/dev/urandom of=/$TESTPOOL2/bigfile bs=1M count=400
+log_must zpool export $TESTPOOL2
+log_must zpool import -d $TEST_BASE_DIR $TESTPOOL2
+
+BAD_VDEV1=$TEST_BASE_DIR/vdev.$$.7
+BAD_VDEV2=$TEST_BASE_DIR/vdev.$$.8
+BAD_VDEV3=$TEST_BASE_DIR/vdev.$$.9
+
+# Initial state should not be sitting out
+log_must eval [[ "$(get_vdev_prop autosit $TESTPOOL2 draid2-0)" == "on" ]]
+log_must eval [[ "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV1)" == "off" ]]
+log_must eval [[ "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV2)" == "off" ]]
+log_must eval [[ "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV3)" == "off" ]]
+
+# Delay our reads 200ms to trigger sit out
+log_must zinject -d $BAD_VDEV1 -D200:1 -T read $TESTPOOL2
+
+# Do some reads and wait for us to sit out
+for i in {0..99} ; do
+ dd if=/$TESTPOOL2/bigfile skip=$i bs=2M count=1 of=/dev/null &
+ dd if=/$TESTPOOL2/bigfile skip=$((i + 100)) bs=2M count=1 of=/dev/null
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV1)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+done
+log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV1)" == "on"
+
+log_must zinject -d $BAD_VDEV2 -D200:1 -T read $TESTPOOL2
+# Do some reads and wait for us to sit out
+for i in {0..99} ; do
+ dd if=/$TESTPOOL2/bigfile skip=$i bs=2M count=1 of=/dev/null &
+ dd if=/$TESTPOOL2/bigfile skip=$((i + 100)) bs=2M count=1 of=/dev/null
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV2)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+done
+log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV2)" == "on"
+
+log_must zinject -d $BAD_VDEV3 -D200:1 -T read $TESTPOOL2
+# Do some reads and wait for us to sit out
+for i in {0..99} ; do
+ dd if=/$TESTPOOL2/bigfile skip=$i bs=2M count=1 of=/dev/null &
+ dd if=/$TESTPOOL2/bigfile skip=$((i + 100)) bs=2M count=1 of=/dev/null
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV3)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+done
+log_must test "$(get_vdev_prop sit_out $TESTPOOL2 $BAD_VDEV3)" == "off"
+
+
+log_pass "sit_out works correctly"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_synchronous_zedlet.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_synchronous_zedlet.ksh
new file mode 100755
index 000000000000..6b732ea96d0c
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/events/zed_synchronous_zedlet.ksh
@@ -0,0 +1,149 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+# Verify ZED synchronous zedlets work as expected
+#
+# STRATEGY:
+# 1. Create a scrub_start zedlet that runs quickly
+# 2. Create a scrub_start zedlet that runs slowly (takes seconds)
+# 3. Create a scrub_finish zedlet that is synchronous and runs slowly
+# 4. Create a trim_start zedlet that runs quickly
+# 4. Scrub the pool
+# 5. Trim the pool
+# 6. Verify the synchronous scrub_finish zedlet waited for the scrub_start
+# zedlets to finish (including the slow one). If the scrub_finish zedlet
+# was not synchronous, it would have completed before the slow scrub_start
+# zedlet.
+# 7. Verify the trim_start zedlet waited for the slow synchronous scrub_finish
+# zedlet to complete.
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/events/events_common.kshlib
+
+verify_runnable "both"
+
+OUR_ZEDLETS="scrub_start-async.sh scrub_start-slow.sh scrub_finish-sync-slow.sh trim_start-async.sh"
+
+OUTFILE="$TEST_BASE_DIR/zed_synchronous_zedlet_lines"
+TESTPOOL2=testpool2
+
+function cleanup
+{
+ zed_stop
+
+ for i in $OUR_ZEDLETS ; do
+ log_must rm -f $ZEDLET_DIR/$i
+ done
+ destroy_pool $TESTPOOL2
+ log_must rm -f $TEST_BASE_DIR/vdev-file-sync-zedlet
+ log_must rm -f $OUTFILE
+}
+
+log_assert "Verify ZED synchronous zedlets work as expected"
+
+log_onexit cleanup
+
+# Make a pool
+log_must truncate -s 100M $TEST_BASE_DIR/vdev-file-sync-zedlet
+log_must zpool create $TESTPOOL2 $TEST_BASE_DIR/vdev-file-sync-zedlet
+
+# Do an initial scrub
+log_must zpool scrub -w $TESTPOOL2
+
+log_must zpool events -c
+
+mkdir -p $ZEDLET_DIR
+
+# Create zedlets
+cat << EOF > $ZEDLET_DIR/scrub_start-async.sh
+#!/bin/ksh -p
+echo "\$(date) \$(basename \$0)" >> $OUTFILE
+EOF
+
+cat << EOF > $ZEDLET_DIR/scrub_start-slow.sh
+#!/bin/ksh -p
+sleep 3
+echo "\$(date) \$(basename \$0)" >> $OUTFILE
+EOF
+
+cat << EOF > $ZEDLET_DIR/scrub_finish-sync-slow.sh
+#!/bin/ksh -p
+sleep 3
+echo "\$(date) \$(basename \$0)" >> $OUTFILE
+EOF
+
+cat << EOF > $ZEDLET_DIR/trim_start-async.sh
+#!/bin/ksh -p
+echo "\$(date) \$(basename \$0)" >> $OUTFILE
+EOF
+
+for i in $OUR_ZEDLETS ; do
+ log_must chmod +x $ZEDLET_DIR/$i
+done
+
+log_must zed_start
+
+# Do a scrub - it should be instantaneous.
+log_must zpool scrub -w $TESTPOOL2
+
+# Start off a trim immediately after scrubiung. The trim should be
+# instantaneous and generate a trimp_start event. This will happen in parallel
+# with the slow 'scrub_finish-sync-slow.sh' zedlet still running.
+log_must zpool trim -w $TESTPOOL2
+
+# Wait for scrub_finish event to happen for sanity. This is the *event*, not
+# the completion of zedlets for the event.
+log_must file_wait_event $ZED_DEBUG_LOG 'sysevent\.fs\.zfs\.trim_finish' 10
+
+# At a minimum, scrub_start-slow.sh + scrub_finish-sync-slow.sh will take a
+# total of 6 seconds to run, so wait 7 sec to be sure.
+sleep 7
+
+# If our zedlets were run in the right order, with sync correctly honored, you
+# will see this ordering in $OUTFILE:
+#
+# Fri May 16 12:04:23 PDT 2025 scrub_start-async.sh
+# Fri May 16 12:04:26 PDT 2025 scrub_start-slow.sh
+# Fri May 16 12:04:31 PDT 2025 scrub_finish-sync-slow.sh
+# Fri May 16 12:04:31 PDT 2025 trim_start-async.sh
+#
+# Check for this ordering
+
+# Get a list of just the script names in the order they were executed
+# from OUTFILE
+lines="$(echo $(grep -Eo '(scrub|trim)_.+\.sh$' $OUTFILE))"
+
+# Compare it to the ordering we expect
+expected="\
+scrub_start-async.sh \
+scrub_start-slow.sh \
+scrub_finish-sync-slow.sh \
+trim_start-async.sh"
+log_must test "$lines" == "$expected"
+
+log_pass "Verified synchronous zedlets"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh
index ef49a5d50f6c..45848bec1f5a 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_001_pos.ksh
@@ -86,7 +86,7 @@ log_must zpool set autoreplace=on $TESTPOOL
# Add some data to the pool
log_must zfs create $TESTPOOL/fs
-log_must fill_fs /$TESTPOOL/fs 4 100 4096 512 Z
+log_must fill_fs /$TESTPOOL/fs 4 100 4096 512 R
log_must zpool export $TESTPOOL
# Record the partition UUID for later comparison
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_002_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_002_pos.ksh
index a77957f32255..878b4e450340 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_002_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/auto_replace_002_pos.ksh
@@ -119,7 +119,7 @@ log_must zpool set autoreplace=on $TESTPOOL
# Add some data to the pool
log_must zfs create $TESTPOOL/fs
-log_must fill_fs /$TESTPOOL/fs 4 100 4096 512 Z
+log_must fill_fs /$TESTPOOL/fs 4 100 4096 512 R
log_must zpool export $TESTPOOL
# Record the partition UUID for later comparison
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/fault_limits.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/fault_limits.ksh
index 1b3310edb98b..45b041503e22 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/fault_limits.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/fault_limits.ksh
@@ -67,7 +67,7 @@ log_must zpool create -f ${TESTPOOL} raidz${PARITY} ${disks[1..$((VDEV_CNT - 1))
# Add some data to the pool
log_must zfs create $TESTPOOL/fs
MNTPOINT="$(get_prop mountpoint $TESTPOOL/fs)"
-log_must fill_fs $MNTPOINT $PARITY 200 32768 1000 Z
+log_must fill_fs $MNTPOINT $PARITY 200 32768 100 R
sync_pool $TESTPOOL
# Replace the last child vdev to form a replacing vdev
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/suspend_on_probe_errors.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/suspend_on_probe_errors.ksh
index 340994bb60c5..b5df1c7e37f8 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/suspend_on_probe_errors.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fault/suspend_on_probe_errors.ksh
@@ -101,7 +101,7 @@ sync_pool $TESTPOOL
log_must zfs create $TESTPOOL/fs
MNTPOINT="$(get_prop mountpoint $TESTPOOL/fs)"
SECONDS=0
-log_must fill_fs $MNTPOINT 1 200 4096 10 Z
+log_must fill_fs $MNTPOINT 1 200 4096 10 R
log_note "fill_fs took $SECONDS seconds"
sync_pool $TESTPOOL
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mount/mount_loopback.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mount/mount_loopback.ksh
new file mode 100755
index 000000000000..86adef7ea032
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/mount/mount_loopback.ksh
@@ -0,0 +1,111 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+# Copyright (c) 2025 by Lawrence Livermore National Security, LLC.
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that we can make an xfs filesystem on a ZFS-backed loopback device.
+#
+# See:
+# https://github.com/openzfs/zfs/pull/17298
+# https://github.com/openzfs/zfs/issues/17277
+#
+# STRATEGY:
+# 1. Make a pool
+# 2. Make a file on the pool or create zvol
+# 3. Mount the file/zvol behind a loopback device
+# 4. Create & mount an xfs filesystem on the loopback device
+
+function cleanup
+{
+ if [ -d $TEST_BASE_DIR/mnt ] ; then
+ umount $TEST_BASE_DIR/mnt
+ log_must rmdir $TEST_BASE_DIR/mnt
+ fi
+ if [ -n "$DEV" ] ; then
+ log_must losetup -d $DEV
+ fi
+ destroy_pool $TESTPOOL2
+ log_must rm -f $TEST_BASE_DIR/file1
+}
+
+if [ ! -x "$(which mkfs.xfs)" ] ; then
+ log_unsupported "No mkfs.xfs binary"
+fi
+
+if [ ! -d /lib/modules/$(uname -r)/kernel/fs/xfs ] && \
+ ! grep -qE '\sxfs$' /proc/filesystems ; then
+ log_unsupported "No XFS kernel support"
+fi
+
+log_assert "Make an xfs filesystem on a ZFS-backed loopback device"
+log_onexit cleanup
+
+# fio options
+export NUMJOBS=2
+export RUNTIME=3
+export PERF_RANDSEED=1234
+export PERF_COMPPERCENT=66
+export PERF_COMPCHUNK=0
+export BLOCKSIZE=128K
+export SYNC_TYPE=0
+export FILE_SIZE=$(( 1024 * 1024 ))
+
+function do_test
+{
+ imgfile=$1
+ log_note "Running test on $imgfile"
+ log_must losetup -f $imgfile
+ DEV=$(losetup --associated $imgfile | grep -Eo '^/dev/loop[0-9]+')
+ log_must mkfs.xfs $DEV
+ mkdir $TEST_BASE_DIR/mnt
+ log_must mount $DEV $TEST_BASE_DIR/mnt
+ export DIRECTORY=$TEST_BASE_DIR/mnt
+
+ for d in 0 1 ; do
+ # fio options
+ export DIRECT=$d
+ log_must fio $FIO_SCRIPTS/mkfiles.fio
+ log_must fio $FIO_SCRIPTS/random_reads.fio
+ done
+ log_must umount $TEST_BASE_DIR/mnt
+ log_must rmdir $TEST_BASE_DIR/mnt
+ log_must losetup -d $DEV
+ DEV=""
+}
+
+log_must truncate -s 1G $TEST_BASE_DIR/file1
+log_must zpool create $TESTPOOL2 $TEST_BASE_DIR/file1
+log_must truncate -s 512M /$TESTPOOL2/img
+do_test /$TESTPOOL2/img
+log_must rm /$TESTPOOL2/img
+log_must zfs create -V 512M $TESTPOOL2/vol
+
+blkdev="$ZVOL_DEVDIR/$TESTPOOL2/vol"
+block_device_wait $blkdev
+do_test $blkdev
+
+log_pass "Verified xfs filesystem on a ZFS-backed loopback device"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh
index 3249bd93d5ce..a1da4a8631e1 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/refreserv/refreserv_raidz.ksh
@@ -17,6 +17,7 @@
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/refreserv/refreserv.cfg
+. $STF_SUITE/tests/functional/zvol/zvol_misc/zvol_misc_common.kshlib
#
# DESCRIPTION:
@@ -24,7 +25,7 @@
#
# STRATEGY:
# 1. Create a pool with a single raidz vdev
-# 2. For each block size [512b, 1k, 128k] or [4k, 8k, 128k]
+# 2. For each block size [4k, 8k, 128k]
# - create a volume
# - fully overwrite it
# - verify that referenced is less than or equal to reservation
@@ -38,6 +39,7 @@
# 1. This test will use up to 14 disks but can cover the key concepts with
# 5 disks.
# 2. If the disks are a mixture of 4Kn and 512n/512e, failures are likely.
+# Therefore, when creating the pool we specify 4Kn sectors.
#
verify_runnable "global"
@@ -60,29 +62,10 @@ log_onexit cleanup
poolexists "$TESTPOOL" && log_must_busy zpool destroy "$TESTPOOL"
-# Testing tiny block sizes on ashift=12 pools causes so much size inflation
-# that small test disks may fill before creating small volumes. However,
-# testing 512b and 1K blocks on ashift=9 pools is an ok approximation for
-# testing the problems that arise from 4K and 8K blocks on ashift=12 pools.
-if is_freebsd; then
- bps=$(diskinfo -v ${alldisks[0]} | awk '/sectorsize/ { print $1 }')
-elif is_linux; then
- bps=$(lsblk -nrdo min-io /dev/${alldisks[0]})
-fi
-log_must test "$bps" -eq 512 -o "$bps" -eq 4096
-case "$bps" in
-512)
- allshifts=(9 10 17)
- maxpct=151
- ;;
-4096)
- allshifts=(12 13 17)
- maxpct=110
- ;;
-*)
- log_fail "bytes/sector: $bps != (512|4096)"
- ;;
-esac
+ashift=12
+allshifts=(12 13 17)
+maxpct=110
+
log_note "Testing in ashift=${allshifts[0]} mode"
# This loop handles all iterations of steps 1 through 4 described in strategy
@@ -99,18 +82,21 @@ for parity in 1 2 3; do
continue
fi
- log_must zpool create -O compression=off "$TESTPOOL" "$raid" "${disks[@]}"
+ log_must zpool create -o ashift=$ashift "$TESTPOOL" "$raid" "${disks[@]}"
for bits in "${allshifts[@]}"; do
vbs=$((1 << bits))
log_note "Testing $raid-$ndisks volblocksize=$vbs"
- vol=$TESTPOOL/$TESTVOL
+ vol=$TESTPOOL/$TESTVOL-$vbs
+ zdev=$ZVOL_DEVDIR/$vol
log_must zfs create -V ${volsize}m \
-o volblocksize=$vbs "$vol"
- block_device_wait "/dev/zvol/$vol"
- log_must dd if=/dev/zero of=/dev/zvol/$vol \
- bs=1024k count=$volsize
+ block_device_wait $zdev
+ blockdev_exists $zdev
+
+ log_must timeout 120 dd if=/dev/urandom of=$zdev \
+ bs=1024k count=$volsize status=progress
sync_pool $TESTPOOL
ref=$(zfs get -Hpo value referenced "$vol")
@@ -126,7 +112,7 @@ for parity in 1 2 3; do
log_must test "$deltapct" -le $maxpct
log_must_busy zfs destroy "$vol"
- block_device_wait
+ blockdev_missing $zdev
done
log_must_busy zpool destroy "$TESTPOOL"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/attach_resilver_sit_out.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/attach_resilver_sit_out.ksh
new file mode 100755
index 000000000000..6820aba184b7
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/attach_resilver_sit_out.ksh
@@ -0,0 +1,189 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+# Copyright (c) 2025, Klara, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/replacement/replacement.cfg
+
+#
+# DESCRIPTION:
+# Attaching disks while a disk is sitting out reads should pass
+#
+# STRATEGY:
+# 1. Create raidz pools
+# 2. Make one disk slower and trigger a read sit out for that disk
+# 3. Start some random I/O
+# 4. Attach a disk to the pool.
+# 5. Verify the integrity of the file system and the resilvering.
+
+verify_runnable "global"
+
+save_tunable READ_SIT_OUT_SECS
+set_tunable32 READ_SIT_OUT_SECS 120
+save_tunable SIT_OUT_CHECK_INTERVAL
+set_tunable64 SIT_OUT_CHECK_INTERVAL 20
+
+function cleanup
+{
+ restore_tunable READ_SIT_OUT_SECS
+ restore_tunable SIT_OUT_CHECK_INTERVAL
+ log_must zinject -c all
+ log_must zpool events -c
+
+ if [[ -n "$child_pids" ]]; then
+ for wait_pid in $child_pids; do
+ kill $wait_pid
+ done
+ fi
+
+ if poolexists $TESTPOOL1; then
+ destroy_pool $TESTPOOL1
+ fi
+
+ [[ -e $TESTDIR ]] && log_must rm -rf $TESTDIR/*
+}
+
+log_assert "Replacing a disk during I/O with a sit out completes."
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
+
+[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
+
+[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
+
+[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
+
+[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
+
+options="$options -r "
+
+[[ -n "$options" ]] && options_display=$options
+
+child_pids=""
+
+function attach_test
+{
+ typeset vdev=$1
+ typeset disk=$2
+
+ typeset i=0
+ while [[ $i -lt $iters ]]; do
+ log_note "Invoking file_trunc with: $options_display on $TESTFILE.$i"
+ file_trunc $options $TESTDIR/$TESTFILE.$i &
+ typeset pid=$!
+
+ sleep 1
+
+ child_pids="$child_pids $pid"
+ ((i = i + 1))
+ done
+
+ # attach disk with a slow drive still present
+ SECONDS=0
+ log_must zpool attach -w $TESTPOOL1 $vdev $disk
+ log_note took $SECONDS seconds to attach disk
+
+ for wait_pid in $child_pids
+ do
+ kill $wait_pid
+ done
+ child_pids=""
+
+ log_must zinject -c all
+ log_must zpool export $TESTPOOL1
+ log_must zpool import -d $TESTDIR $TESTPOOL1
+ log_must zfs umount $TESTPOOL1/$TESTFS1
+ log_must zdb -cdui $TESTPOOL1/$TESTFS1
+ log_must zfs mount $TESTPOOL1/$TESTFS1
+ verify_pool $TESTPOOL1
+}
+
+DEVSIZE="150M"
+specials_list=""
+i=0
+while [[ $i != 10 ]]; do
+ truncate -s $DEVSIZE $TESTDIR/$TESTFILE1.$i
+ specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
+
+ ((i = i + 1))
+done
+
+slow_disk=$TESTDIR/$TESTFILE1.3
+log_must truncate -s $DEVSIZE $TESTDIR/$REPLACEFILE
+
+# Test file size in MB
+count=200
+
+for type in "raidz1" "raidz2" "raidz3" ; do
+ create_pool $TESTPOOL1 $type $specials_list
+ log_must zpool set autosit=on $TESTPOOL1 "${type}-0"
+ log_must zfs create -o primarycache=none -o recordsize=512K \
+ $TESTPOOL1/$TESTFS1
+ log_must zfs set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+ log_must dd if=/dev/urandom of=/$TESTDIR1/bigfile bs=1M count=$count
+
+ # Make one disk 100ms slower to trigger a sit out
+ log_must zinject -d $slow_disk -D100:1 -T read $TESTPOOL1
+
+ # Do some reads and wait for sit out on slow disk
+ SECONDS=0
+ typeset -i size=0
+ for i in $(seq 1 $count) ; do
+ dd if=/$TESTDIR1/bigfile skip=$i bs=1M count=1 of=/dev/null
+ size=$i
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL1 $slow_disk)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+ done
+
+ log_must test "$(get_vdev_prop sit_out $TESTPOOL1 $slow_disk)" == "on"
+ log_note took $SECONDS seconds to reach sit out reading ${size}M
+ log_must zpool status -s $TESTPOOL1
+
+ typeset top=$(zpool status -j | jq -r ".pools.$TESTPOOL1.vdevs[].vdevs[].name")
+ attach_test $top $TESTDIR/$REPLACEFILE
+
+ log_must eval "zpool iostat -v $TESTPOOL1 | grep \"$REPLACEFILE\""
+
+ destroy_pool $TESTPOOL1
+ log_must rm -rf /$TESTPOOL1
+done
+
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/replace_resilver_sit_out.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/replace_resilver_sit_out.ksh
new file mode 100755
index 000000000000..4109dbaf45ac
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/replacement/replace_resilver_sit_out.ksh
@@ -0,0 +1,199 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+# Copyright (c) 2025, Klara, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/replacement/replacement.cfg
+
+#
+# DESCRIPTION:
+# Replacing disks while a disk is sitting out reads should pass
+#
+# STRATEGY:
+# 1. Create raidz and draid pools
+# 2. Make one disk slower and trigger a read sit out for that disk
+# 3. Start some random I/O
+# 4. Replace a disk in the pool with another disk.
+# 5. Verify the integrity of the file system and the resilvering.
+#
+
+verify_runnable "global"
+
+save_tunable READ_SIT_OUT_SECS
+set_tunable32 READ_SIT_OUT_SECS 120
+save_tunable SIT_OUT_CHECK_INTERVAL
+set_tunable64 SIT_OUT_CHECK_INTERVAL 20
+
+function cleanup
+{
+ restore_tunable READ_SIT_OUT_SECS
+ restore_tunable SIT_OUT_CHECK_INTERVAL
+ log_must zinject -c all
+ log_must zpool events -c
+
+ if [[ -n "$child_pids" ]]; then
+ for wait_pid in $child_pids
+ do
+ kill $wait_pid
+ done
+ fi
+
+ if poolexists $TESTPOOL1; then
+ destroy_pool $TESTPOOL1
+ fi
+
+ [[ -e $TESTDIR ]] && log_must rm -rf $TESTDIR/*
+}
+
+log_assert "Replacing a disk during I/O with a sit out completes."
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
+
+[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
+
+[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
+
+[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
+
+[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
+
+options="$options -r "
+
+[[ -n "$options" ]] && options_display=$options
+
+child_pids=""
+
+function replace_test
+{
+ typeset -i iters=2
+ typeset disk1=$1
+ typeset disk2=$2
+ typeset repl_type=$3
+
+ typeset i=0
+ while [[ $i -lt $iters ]]; do
+ log_note "Invoking file_trunc with: $options_display on $TESTFILE.$i"
+ file_trunc $options $TESTDIR/$TESTFILE.$i &
+ typeset pid=$!
+
+ sleep 1
+
+ child_pids="$child_pids $pid"
+ ((i = i + 1))
+ done
+
+ typeset repl_flag="-w"
+ if [[ "$repl_type" == "seq" ]]; then
+ repl_flag="-ws"
+ fi
+ # replace disk with a slow drive still present
+ SECONDS=0
+ log_must zpool replace $repl_flag $TESTPOOL1 $disk1 $disk2
+ log_note took $SECONDS seconds to replace disk
+
+ for wait_pid in $child_pids
+ do
+ kill $wait_pid
+ done
+ child_pids=""
+
+ log_must zinject -c all
+ log_must zpool export $TESTPOOL1
+ log_must zpool import -d $TESTDIR $TESTPOOL1
+ log_must zfs umount $TESTPOOL1/$TESTFS1
+ log_must zdb -cdui $TESTPOOL1/$TESTFS1
+ log_must zfs mount $TESTPOOL1/$TESTFS1
+ verify_pool $TESTPOOL1
+}
+
+DEVSIZE="150M"
+specials_list=""
+i=0
+while [[ $i != 10 ]]; do
+ log_must truncate -s $DEVSIZE $TESTDIR/$TESTFILE1.$i
+ specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
+
+ ((i = i + 1))
+done
+
+slow_disk=$TESTDIR/$TESTFILE1.3
+log_must truncate -s $DEVSIZE $TESTDIR/$REPLACEFILE
+
+# Test file size in MB
+count=400
+
+for type in "raidz2" "raidz3" "draid2"; do
+ create_pool $TESTPOOL1 $type $specials_list
+ log_must zpool set autosit=on $TESTPOOL1 "${type}-0"
+ log_must zfs create -o primarycache=none -o recordsize=512K \
+ $TESTPOOL1/$TESTFS1
+ log_must zfs set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+ log_must dd if=/dev/urandom of=/$TESTDIR1/bigfile bs=1M count=$count
+
+ # Make one disk 100ms slower to trigger a sit out
+ log_must zinject -d $slow_disk -D100:1 -T read $TESTPOOL1
+
+ # Do some reads and wait for sit out on slow disk
+ SECONDS=0
+ typeset -i size=0
+ for i in $(seq 1 $count) ; do
+ dd if=/$TESTDIR1/bigfile skip=$i bs=1M count=1 of=/dev/null
+ size=$i
+
+ sit_out=$(get_vdev_prop sit_out $TESTPOOL1 $slow_disk)
+ if [[ "$sit_out" == "on" ]] ; then
+ break
+ fi
+ done
+ log_must test "$(get_vdev_prop sit_out $TESTPOOL1 $slow_disk)" == "on"
+ log_note took $SECONDS seconds to reach sit out reading ${size}M
+ log_must zpool status -s $TESTPOOL1
+
+ typeset repl_type="replace"
+ if [[ "$type" == "draid2" && $((RANDOM % 2)) -eq 0 ]]; then
+ repl_type="seq"
+ fi
+ replace_test $TESTDIR/$TESTFILE1.1 $TESTDIR/$REPLACEFILE $repl_type
+
+ log_must eval "zpool iostat -v $TESTPOOL1 | grep \"$REPLACEFILE\""
+
+ destroy_pool $TESTPOOL1
+ log_must rm -rf /$TESTPOOL1
+done
+
+log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh
index 26153aafbc02..0e79e9b8b70c 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh
@@ -39,6 +39,6 @@
verify_runnable "global"
# create a pool without any features
-log_must mkfile 128m $TMPDEV
+log_must truncate -s $MINVDEVSIZE $TMPDEV
log_pass
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh
index d6bd69b7e134..e81d07794689 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh
@@ -35,17 +35,19 @@
verify_runnable "global"
-TESTFILE="$TESTDIR/file.bin"
-
log_assert "User accounting upgrade should not be executed on readonly pool"
log_onexit cleanup_upgrade
# 1. Create a pool with the feature@userobj_accounting disabled to simulate
# a legacy pool from a previous ZFS version.
-log_must zpool create -d -m $TESTDIR $TESTPOOL $TMPDEV
+log_must zpool create -d $TESTPOOL $TMPDEV
+log_must zfs create $TESTPOOL/$TESTFS
+
+MNTPNT=$(get_prop mountpoint $TESTPOOL/$TESTFS)
+TESTFILE="$MNTPNT/file.bin"
# 2. Create a file on the "legecy" dataset
-log_must touch $TESTDIR/file.bin
+log_must touch $TESTFILE
# 3. Enable feature@userobj_accounting on the pool and verify it is only
# "enabled" and not "active": upgrading starts when the filesystem is mounted
@@ -54,12 +56,12 @@ log_must test "enabled" == "$(get_pool_prop 'feature@userobj_accounting' $TESTPO
# 4. Export the pool and re-import is readonly, without mounting any filesystem
log_must zpool export $TESTPOOL
-log_must zpool import -o readonly=on -N -d "$(dirname $TMPDEV)" $TESTPOOL
+log_must zpool import -o readonly=on -N -d $TEST_BASE_DIR $TESTPOOL
# 5. Try to mount the root dataset manually without the "ro" option, then verify
# filesystem status and the pool feature status (not "active") to ensure the
# pool "readonly" status is enforced.
-log_must mount -t zfs -o zfsutil $TESTPOOL $TESTDIR
+log_must zfs mount -R $TESTPOOL
log_must stat "$TESTFILE"
log_mustnot touch "$TESTFILE"
log_must test "enabled" == "$(get_pool_prop 'feature@userobj_accounting' $TESTPOOL)"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh
new file mode 100755
index 000000000000..d4c9a0a41816
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/xattr/xattr_014_pos.ksh
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or https://opensource.org/licenses/CDDL-1.0.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2025 by Klara, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# The default xattr should be shown as 'sa', not 'on', for clarity.
+#
+# STRATEGY:
+# 1. Create a filesystem.
+# 2. Verify that the xattra is shown as 'sa'.
+# 3. Manually set the value to 'dir', 'sa', 'on', and 'off'.
+# 4. Verify that it is shown as 'dir', 'sa', 'sa', and 'off.
+#
+
+log_assert "The default and specific xattr values are displayed correctly."
+
+set -A args "dir" "sa" "on" "off"
+set -A display "dir" "sa" "sa" "off"
+
+log_must eval "[[ 'sa' == '$(zfs get -Hpo value xattr $TESTPOOL)' ]]"
+
+for i in `seq 0 3`; do
+ log_must zfs set xattr="${args[$i]}" $TESTPOOL
+ log_must eval "[[ '${display[$i]}' == '$(zfs get -Hpo value xattr $TESTPOOL)' ]]"
+done
+log_pass "The default and specific xattr values are displayed correctly."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh
index 571a698eb63a..502ebada22dc 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_fua.ksh
@@ -50,17 +50,53 @@ fi
typeset datafile1="$(mktemp -t zvol_misc_fua1.XXXXXX)"
typeset datafile2="$(mktemp -t zvol_misc_fua2.XXXXXX)"
+typeset datafile3="$(mktemp -t zvol_misc_fua3_log.XXXXXX)"
typeset zvolpath=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+typeset DISK1=${DISKS%% *}
function cleanup
{
- rm "$datafile1" "$datafile2"
+ log_must zpool remove $TESTPOOL $datafile3
+ rm "$datafile1" "$datafile2" "$datafile2"
+}
+
+# Prints the total number of sync writes for a vdev
+# $1: vdev
+function get_sync
+{
+ zpool iostat -p -H -v -r $TESTPOOL $1 | \
+ awk '/[0-9]+$/{s+=$4+$5} END{print s}'
}
function do_test {
# Wait for udev to create symlinks to our zvol
block_device_wait $zvolpath
+ # Write using sync (creates FLUSH calls after writes, but not FUA)
+ old_vdev_writes=$(get_sync $DISK1)
+ old_log_writes=$(get_sync $datafile3)
+
+ log_must fio --name=write_iops --size=5M \
+ --ioengine=libaio --verify=0 --bs=4K \
+ --iodepth=1 --rw=randwrite --group_reporting=1 \
+ --filename=$zvolpath --sync=1
+
+ vdev_writes=$(( $(get_sync $DISK1) - $old_vdev_writes))
+ log_writes=$(( $(get_sync $datafile3) - $old_log_writes))
+
+ # When we're doing sync writes, we should see many more writes go to
+ # the log vs the first vdev. Experiments show anywhere from a 160-320x
+ # ratio of writes to the log vs the first vdev (due to some straggler
+ # writes to the first vdev).
+ #
+ # Check that we have a large ratio (100x) of sync writes going to the
+ # log device
+ ratio=$(($log_writes / $vdev_writes))
+ log_note "Got $log_writes log writes, $vdev_writes vdev writes."
+ if [ $ratio -lt 100 ] ; then
+ log_fail "Expected > 100x more log writes than vdev writes. "
+ fi
+
# Create a data file
log_must dd if=/dev/urandom of="$datafile1" bs=1M count=5
@@ -81,6 +117,8 @@ log_assert "Verify that a ZFS volume can do Force Unit Access (FUA)"
log_onexit cleanup
log_must zfs set compression=off $TESTPOOL/$TESTVOL
+log_must truncate -s 100M $datafile3
+log_must zpool add $TESTPOOL log $datafile3
log_note "Testing without blk-mq"