git: 6bf158defbcb - releng/15.0 - zfs: merge openzfs/zfs@814f9afba (zfs-2.4-release) into stable/15

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Tue, 28 Oct 2025 21:23:36 UTC
The branch releng/15.0 has been updated by cperciva:

URL: https://cgit.FreeBSD.org/src/commit/?id=6bf158defbcb2f3c948b28394388179c7e95bd8b

commit 6bf158defbcb2f3c948b28394388179c7e95bd8b
Author:     Martin Matuska <mm@FreeBSD.org>
AuthorDate: 2025-10-25 08:14:36 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2025-10-28 21:22:49 +0000

    zfs: merge openzfs/zfs@814f9afba (zfs-2.4-release) into stable/15
    
    OpenZFS 2.4.0 rc3
    
    Notable upstream pull request merges:
     #17750 964dfc317 FreeBSD: Correct _PC_MIN_HOLE_SIZE
     #17793 b9d1e28a7 ddt prune: Add SCL_ZIO deadlock workaround
     #17799 1585a10a8 Make mount/share errors non-fatal for zfs create/clone
     #17801 073b34b3e Fix display of default xattr to show 'sa'
     #17803 e09c86cb1 zvol: verify IO type is supported
     #17807 -multiple zpool iostat: fix regressions in "all pools" mode
                      after #17786
     #17826 b9356f06e Explicit set ashift for non-leaf vdevs
     #17830 f0bff230f Suppress some ashift warnings
     #17833 c1f55bff8 Fix the type of the raidz_outlier_check_interval_ms
                      parameter
     #17836 799bda73e Fix return value for setting zvol threading
     #17834 f0c76f8a7 libzpool/cmn_err: remove suppression, add stop option,
                      cleanup
     #17843 1956417b5 mmap_seek: print error code and text on failure
     #17847 7987d4deb Update device removal documentation
     #17851 6f6e1c90a FreeBSD: zfs_getpages: Don't zero freshly allocated pages
    
    Approved by:    re (cperciva)
    Obtained from:  OpenZFS
    OpenZFS commit: 814f9afba7d6714bd63f18ac808955b61d37f9f0
    OpenZFS tag:    zfs-2.4.0-rc3
    
    (cherry picked from commit ce7e1f86a1810038f142c5c68b787c47252b39c5)
---
 .../.github/ISSUE_TEMPLATE/feature_request.md      |   2 +-
 .../.github/workflows/scripts/qemu-2-start.sh      |  11 +-
 sys/contrib/openzfs/.github/workflows/zfs-qemu.yml |   2 +-
 sys/contrib/openzfs/META                           |   2 +-
 sys/contrib/openzfs/cmd/zdb/zdb.c                  | 191 +++++++++++++++++++--
 sys/contrib/openzfs/cmd/zfs/zfs_main.c             |  10 +-
 sys/contrib/openzfs/cmd/zinject/zinject.c          |  81 +++++++--
 sys/contrib/openzfs/cmd/zpool/zpool_iter.c         |  19 +-
 sys/contrib/openzfs/cmd/zpool/zpool_main.c         |   1 +
 sys/contrib/openzfs/cmd/zpool/zpool_vdev.c         |  64 +++----
 .../config/kernel-block-device-operations.m4       |  34 ++++
 sys/contrib/openzfs/config/kernel-drop-inode.m4    |  24 +++
 sys/contrib/openzfs/config/kernel-namespace.m4     |  31 ++++
 .../openzfs/config/kernel-userns-capabilities.m4   |  79 ---------
 sys/contrib/openzfs/config/kernel-writeback.m4     |  58 +++++++
 sys/contrib/openzfs/config/kernel-writepage_t.m4   |  26 ---
 sys/contrib/openzfs/config/kernel.m4               |   8 +-
 sys/contrib/openzfs/contrib/intel_qat/readme.md    |   2 +-
 sys/contrib/openzfs/etc/init.d/README.md           |   2 +-
 sys/contrib/openzfs/include/libzfs.h               |   2 +
 .../include/os/linux/kernel/linux/vfs_compat.h     |   7 +
 sys/contrib/openzfs/include/sys/spa.h              |   2 +-
 sys/contrib/openzfs/include/sys/zfs_ioctl.h        |   1 +
 sys/contrib/openzfs/include/sys/zio.h              |   1 +
 sys/contrib/openzfs/lib/libspl/include/sys/uio.h   |   1 +
 sys/contrib/openzfs/lib/libuutil/libuutil.abi      | 105 +----------
 sys/contrib/openzfs/lib/libzfs/libzfs.abi          | 172 ++++---------------
 sys/contrib/openzfs/lib/libzfs/libzfs_config.c     |  17 ++
 sys/contrib/openzfs/lib/libzfs/libzfs_status.c     |  78 +++++----
 .../openzfs/lib/libzfs_core/libzfs_core.abi        | 105 +----------
 sys/contrib/openzfs/lib/libzpool/kernel.c          |  79 +++++++--
 sys/contrib/openzfs/man/man8/zdb.8                 |  14 ++
 sys/contrib/openzfs/man/man8/zinject.8             |  14 ++
 sys/contrib/openzfs/man/man8/zpool-remove.8        |   4 +-
 .../openzfs/module/icp/algs/sha2/sha2_generic.c    |  41 +++--
 .../openzfs/module/os/freebsd/zfs/zfs_ctldir.c     |   3 +-
 .../openzfs/module/os/freebsd/zfs/zfs_vnops_os.c   |  31 +++-
 sys/contrib/openzfs/module/os/linux/spl/spl-zone.c |  19 +-
 sys/contrib/openzfs/module/os/linux/zfs/abd_os.c   |   9 +
 sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c  |   2 +-
 .../openzfs/module/os/linux/zfs/zfs_vnops_os.c     |   5 +-
 sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c |  74 ++++++++
 .../openzfs/module/os/linux/zfs/zpl_super.c        |   4 +-
 sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c  | 109 ++++++++----
 sys/contrib/openzfs/module/zcommon/zfs_prop.c      |   2 +-
 sys/contrib/openzfs/module/zfs/arc.c               |  17 +-
 sys/contrib/openzfs/module/zfs/mmp.c               |   2 +-
 sys/contrib/openzfs/module/zfs/spa_misc.c          |   8 +-
 sys/contrib/openzfs/module/zfs/vdev_removal.c      |  80 ++++++---
 sys/contrib/openzfs/module/zfs/zio.c               |  35 +++-
 sys/contrib/openzfs/module/zfs/zio_inject.c        |  38 ++++
 sys/contrib/openzfs/module/zfs/zvol.c              |   2 +-
 sys/contrib/openzfs/tests/runfiles/common.run      |   3 +-
 sys/contrib/openzfs/tests/runfiles/sanity.run      |   2 +-
 .../openzfs/tests/zfs-tests/cmd/mmap_seek.c        |  35 ++--
 .../openzfs/tests/zfs-tests/tests/Makefile.am      |   1 +
 .../cli_root/zpool_reopen/zpool_reopen_004_pos.ksh |   2 +
 .../functional/delegate/delegate_common.kshlib     |   6 +-
 .../tests/functional/xattr/xattr_014_pos.ksh       |  53 ++++++
 .../functional/zvol/zvol_misc/zvol_misc_trim.ksh   |   7 +
 60 files changed, 1133 insertions(+), 706 deletions(-)

diff --git a/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md b/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md
index 9b50a4a3d96e..f3d4316f6f67 100644
--- a/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md
@@ -14,7 +14,7 @@ Please check our issue tracker before opening a new feature request.
 Filling out the following template will help other contributors better understand your proposed feature.
 -->
 
-### Describe the feature would like to see added to OpenZFS
+### Describe the feature you would like to see added to OpenZFS
 
 <!--
 Provide a clear and concise description of the feature.
diff --git a/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh b/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh
index 1c608348ffcd..422b3e9df388 100755
--- a/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh
+++ b/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh
@@ -121,7 +121,14 @@ case "$OS" in
     KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
     ;;
   freebsd15-0c)
-    FreeBSD="15.0-ALPHA3"
+    FreeBSD="15.0-ALPHA4"
+    OSNAME="FreeBSD $FreeBSD"
+    OSv="freebsd14.0"
+    URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
+    KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
+    ;;
+  freebsd16-0c)
+    FreeBSD="16.0-CURRENT"
     OSNAME="FreeBSD $FreeBSD"
     OSv="freebsd14.0"
     URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
@@ -287,7 +294,7 @@ else
   while pidof /usr/bin/qemu-system-x86_64 >/dev/null; do
     ssh 2>/dev/null root@vm0 "uname -a" && break
   done
-  ssh root@vm0 "pkg install -y bash ca_root_nss git qemu-guest-agent python3 py311-cloud-init"
+  ssh root@vm0 "env IGNORE_OSVERSION=yes pkg install -y bash ca_root_nss git qemu-guest-agent python3 py311-cloud-init"
   ssh root@vm0 "chsh -s $BASH root"
   ssh root@vm0 'sysrc qemu_guest_agent_enable="YES"'
   ssh root@vm0 'sysrc cloudinit_enable="YES"'
diff --git a/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml b/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml
index 64277dcca236..f1b189062bb7 100644
--- a/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml
+++ b/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml
@@ -68,7 +68,7 @@ jobs:
         # FreeBSD variants of 2025-06:
         # FreeBSD Release: freebsd13-5r, freebsd14-2r, freebsd14-3r
         # FreeBSD Stable:  freebsd13-5s, freebsd14-3s
-        # FreeBSD Current: freebsd15-0c
+        # FreeBSD Current: freebsd15-0c, freebsd16-0c
         os: ${{ fromJson(needs.test-config.outputs.test_os) }}
     runs-on: ubuntu-24.04
     steps:
diff --git a/sys/contrib/openzfs/META b/sys/contrib/openzfs/META
index ddb64774e4c0..2bfa51841cc4 100644
--- a/sys/contrib/openzfs/META
+++ b/sys/contrib/openzfs/META
@@ -2,7 +2,7 @@ Meta:          1
 Name:          zfs
 Branch:        1.0
 Version:       2.4.0
-Release:       rc2
+Release:       rc3
 Release-Tags:  relext
 License:       CDDL
 Author:        OpenZFS
diff --git a/sys/contrib/openzfs/cmd/zdb/zdb.c b/sys/contrib/openzfs/cmd/zdb/zdb.c
index 70a4ed46f263..2560ad045db3 100644
--- a/sys/contrib/openzfs/cmd/zdb/zdb.c
+++ b/sys/contrib/openzfs/cmd/zdb/zdb.c
@@ -106,11 +106,15 @@ extern boolean_t spa_mode_readable_spacemaps;
 extern uint_t zfs_reconstruct_indirect_combinations_max;
 extern uint_t zfs_btree_verify_intensity;
 
+enum {
+	ARG_ALLOCATED = 256,
+	ARG_BLOCK_BIN_MODE,
+	ARG_BLOCK_CLASSES,
+};
+
 static const char cmdname[] = "zdb";
 uint8_t dump_opt[512];
 
-#define	ALLOCATED_OPT	256
-
 typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
 
 static uint64_t *zopt_metaslab = NULL;
@@ -131,6 +135,20 @@ static objset_t *os;
 static boolean_t kernel_init_done;
 static boolean_t corruption_found = B_FALSE;
 
+static enum {
+	BIN_AUTO = 0,
+	BIN_PSIZE,
+	BIN_LSIZE,
+	BIN_ASIZE,
+} block_bin_mode = BIN_AUTO;
+
+static enum {
+	CLASS_NORMAL = 1 << 1,
+	CLASS_SPECIAL = 1 << 2,
+	CLASS_DEDUP = 1 << 3,
+	CLASS_OTHER = 1 << 4,
+} block_classes = 0;
+
 static void snprintf_blkptr_compact(char *, size_t, const blkptr_t *,
     boolean_t);
 static void mos_obj_refd(uint64_t);
@@ -749,6 +767,12 @@ usage(void)
 	(void) fprintf(stderr, "    Options to control amount of output:\n");
 	(void) fprintf(stderr, "        -b --block-stats             "
 	    "block statistics\n");
+	(void) fprintf(stderr, "           --bin=(lsize|psize|asize) "
+	    "bin blocks based on this size in all three columns\n");
+	(void) fprintf(stderr,
+	    "           --class=(normal|special|dedup|other)[,...]\n"
+	    "                                     only consider blocks from "
+	    "these allocation classes\n");
 	(void) fprintf(stderr, "        -B --backup                  "
 	    "backup stream\n");
 	(void) fprintf(stderr, "        -c --checksum                "
@@ -1694,7 +1718,7 @@ dump_metaslab(metaslab_t *msp)
 	    (u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,
 	    (u_longlong_t)space_map_object(sm), freebuf);
 
-	if (dump_opt[ALLOCATED_OPT] ||
+	if (dump_opt[ARG_ALLOCATED] ||
 	    (dump_opt['m'] > 2 && !dump_opt['L'])) {
 		mutex_enter(&msp->ms_lock);
 		VERIFY0(metaslab_load(msp));
@@ -1705,7 +1729,7 @@ dump_metaslab(metaslab_t *msp)
 		dump_metaslab_stats(msp);
 	}
 
-	if (dump_opt[ALLOCATED_OPT]) {
+	if (dump_opt[ARG_ALLOCATED]) {
 		uint64_t off = msp->ms_start;
 		zfs_range_tree_walk(msp->ms_allocatable, dump_allocated,
 		    &off);
@@ -1726,7 +1750,7 @@ dump_metaslab(metaslab_t *msp)
 		    SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
 	}
 
-	if (dump_opt[ALLOCATED_OPT] ||
+	if (dump_opt[ARG_ALLOCATED] ||
 	    (dump_opt['m'] > 2 && !dump_opt['L'])) {
 		metaslab_unload(msp);
 		mutex_exit(&msp->ms_lock);
@@ -5814,6 +5838,34 @@ dump_size_histograms(zdb_cb_t *zcb)
 
 
 	(void) printf("\nBlock Size Histogram\n");
+	switch (block_bin_mode) {
+	case BIN_PSIZE:
+		printf("(note: all categories are binned by %s)\n", "psize");
+		break;
+	case BIN_LSIZE:
+		printf("(note: all categories are binned by %s)\n", "lsize");
+		break;
+	case BIN_ASIZE:
+		printf("(note: all categories are binned by %s)\n", "asize");
+		break;
+	default:
+		printf("(note: all categories are binned separately)\n");
+		break;
+	}
+	if (block_classes != 0) {
+		char buf[256] = "";
+		if (block_classes & CLASS_NORMAL)
+			strlcat(buf, "\"normal\", ", sizeof (buf));
+		if (block_classes & CLASS_SPECIAL)
+			strlcat(buf, "\"special\", ", sizeof (buf));
+		if (block_classes & CLASS_DEDUP)
+			strlcat(buf, "\"dedup\", ", sizeof (buf));
+		if (block_classes & CLASS_OTHER)
+			strlcat(buf, "\"other\", ", sizeof (buf));
+		buf[strlen(buf)-2] = '\0';
+		printf("(note: only blocks in these classes are counted: %s)\n",
+		    buf);
+	}
 	/*
 	 * Print the first line titles
 	 */
@@ -6162,29 +6214,85 @@ skipped:
 		    [BPE_GET_PSIZE(bp)]++;
 		return;
 	}
+
+	if (block_classes != 0) {
+		spa_config_enter(zcb->zcb_spa, SCL_CONFIG, FTAG, RW_READER);
+
+		uint64_t vdev = DVA_GET_VDEV(&bp->blk_dva[0]);
+		uint64_t offset = DVA_GET_OFFSET(&bp->blk_dva[0]);
+		vdev_t *vd = vdev_lookup_top(zcb->zcb_spa, vdev);
+		ASSERT(vd != NULL);
+		metaslab_t *ms = vd->vdev_ms[offset >> vd->vdev_ms_shift];
+		ASSERT(ms != NULL);
+		metaslab_group_t *mg = ms->ms_group;
+		ASSERT(mg != NULL);
+		metaslab_class_t *mc = mg->mg_class;
+		ASSERT(mc != NULL);
+
+		spa_config_exit(zcb->zcb_spa, SCL_CONFIG, FTAG);
+
+		int class;
+		if (mc == spa_normal_class(zcb->zcb_spa)) {
+			class = CLASS_NORMAL;
+		} else if (mc == spa_special_class(zcb->zcb_spa)) {
+			class = CLASS_SPECIAL;
+		} else if (mc == spa_dedup_class(zcb->zcb_spa)) {
+			class = CLASS_DEDUP;
+		} else {
+			class = CLASS_OTHER;
+		}
+
+		if (!(block_classes & class)) {
+			goto hist_skipped;
+		}
+	}
+
 	/*
 	 * The binning histogram bins by powers of two up to
 	 * SPA_MAXBLOCKSIZE rather than creating bins for
 	 * every possible blocksize found in the pool.
 	 */
-	int bin = highbit64(BP_GET_PSIZE(bp)) - 1;
+	int bin;
+
+	/*
+	 * Binning strategy: each bin includes blocks up to and including
+	 * the given size (excluding blocks that fit into the previous bin).
+	 * This way, the "4K" bin includes blocks within the (2K; 4K] range.
+	 */
+#define	BIN(size) (highbit64((size) - 1))
+
+	switch (block_bin_mode) {
+	case BIN_PSIZE: bin = BIN(BP_GET_PSIZE(bp)); break;
+	case BIN_LSIZE: bin = BIN(BP_GET_LSIZE(bp)); break;
+	case BIN_ASIZE: bin = BIN(BP_GET_ASIZE(bp)); break;
+	case BIN_AUTO: break;
+	default: PANIC("bad block_bin_mode"); abort();
+	}
+
+	if (block_bin_mode == BIN_AUTO)
+		bin = BIN(BP_GET_PSIZE(bp));
 
 	zcb->zcb_psize_count[bin]++;
 	zcb->zcb_psize_len[bin] += BP_GET_PSIZE(bp);
 	zcb->zcb_psize_total += BP_GET_PSIZE(bp);
 
-	bin = highbit64(BP_GET_LSIZE(bp)) - 1;
+	if (block_bin_mode == BIN_AUTO)
+		bin = BIN(BP_GET_LSIZE(bp));
 
 	zcb->zcb_lsize_count[bin]++;
 	zcb->zcb_lsize_len[bin] += BP_GET_LSIZE(bp);
 	zcb->zcb_lsize_total += BP_GET_LSIZE(bp);
 
-	bin = highbit64(BP_GET_ASIZE(bp)) - 1;
+	if (block_bin_mode == BIN_AUTO)
+		bin = BIN(BP_GET_ASIZE(bp));
 
 	zcb->zcb_asize_count[bin]++;
 	zcb->zcb_asize_len[bin] += BP_GET_ASIZE(bp);
 	zcb->zcb_asize_total += BP_GET_ASIZE(bp);
 
+#undef BIN
+
+hist_skipped:
 	if (!do_claim)
 		return;
 
@@ -9426,7 +9534,11 @@ main(int argc, char **argv)
 		{"livelist",		no_argument,		NULL, 'y'},
 		{"zstd-headers",	no_argument,		NULL, 'Z'},
 		{"allocated-map",	no_argument,		NULL,
-		    ALLOCATED_OPT},
+		    ARG_ALLOCATED},
+		{"bin",			required_argument,	NULL,
+		    ARG_BLOCK_BIN_MODE},
+		{"class",		required_argument,	NULL,
+		    ARG_BLOCK_CLASSES},
 		{0, 0, 0, 0}
 	};
 
@@ -9457,7 +9569,7 @@ main(int argc, char **argv)
 		case 'u':
 		case 'y':
 		case 'Z':
-		case ALLOCATED_OPT:
+		case ARG_ALLOCATED:
 			dump_opt[c]++;
 			dump_all = 0;
 			break;
@@ -9540,6 +9652,59 @@ main(int argc, char **argv)
 		case 'x':
 			vn_dumpdir = optarg;
 			break;
+		case ARG_BLOCK_BIN_MODE:
+			if (strcmp(optarg, "lsize") == 0) {
+				block_bin_mode = BIN_LSIZE;
+			} else if (strcmp(optarg, "psize") == 0) {
+				block_bin_mode = BIN_PSIZE;
+			} else if (strcmp(optarg, "asize") == 0) {
+				block_bin_mode = BIN_ASIZE;
+			} else {
+				(void) fprintf(stderr,
+				    "--bin=\"%s\" must be one of \"lsize\", "
+				    "\"psize\" or \"asize\"\n", optarg);
+				usage();
+			}
+			break;
+
+		case ARG_BLOCK_CLASSES: {
+			char *buf = strdup(optarg), *tok = buf, *next,
+			    *save = NULL;
+
+			while ((next = strtok_r(tok, ",", &save)) != NULL) {
+				tok = NULL;
+
+				if (strcmp(next, "normal") == 0) {
+					block_classes |= CLASS_NORMAL;
+				} else if (strcmp(next, "special") == 0) {
+					block_classes |= CLASS_SPECIAL;
+				} else if (strcmp(next, "dedup") == 0) {
+					block_classes |= CLASS_DEDUP;
+				} else if (strcmp(next, "other") == 0) {
+					block_classes |= CLASS_OTHER;
+				} else {
+					(void) fprintf(stderr,
+					    "--class=\"%s\" must be a "
+					    "comma-separated list of either "
+					    "\"normal\", \"special\", "
+					    "\"asize\" or \"other\"; "
+					    "got \"%s\"\n",
+					    optarg, next);
+					usage();
+				}
+			}
+
+			if (block_classes == 0) {
+				(void) fprintf(stderr,
+				    "--class= must be a comma-separated "
+				    "list of either \"normal\", \"special\", "
+				    "\"asize\" or \"other\"; got empty\n");
+				usage();
+			}
+
+			free(buf);
+			break;
+		}
 		default:
 			usage();
 			break;
@@ -9582,6 +9747,9 @@ main(int argc, char **argv)
 	 */
 	spa_mode_readable_spacemaps = B_TRUE;
 
+	libspl_set_assert_ok((dump_opt['A'] == 1) || (dump_opt['A'] > 2));
+	zfs_recover = (dump_opt['A'] > 1);
+
 	if (dump_all)
 		verbose = MAX(verbose, 1);
 
@@ -9592,9 +9760,6 @@ main(int argc, char **argv)
 			dump_opt[c] += verbose;
 	}
 
-	libspl_set_assert_ok((dump_opt['A'] == 1) || (dump_opt['A'] > 2));
-	zfs_recover = (dump_opt['A'] > 1);
-
 	argc -= optind;
 	argv += optind;
 	if (argc < 2 && dump_opt['R'])
diff --git a/sys/contrib/openzfs/cmd/zfs/zfs_main.c b/sys/contrib/openzfs/cmd/zfs/zfs_main.c
index b66440c8f9f8..ccdd5ffef8e6 100644
--- a/sys/contrib/openzfs/cmd/zfs/zfs_main.c
+++ b/sys/contrib/openzfs/cmd/zfs/zfs_main.c
@@ -914,7 +914,11 @@ zfs_do_clone(int argc, char **argv)
 			log_history = B_FALSE;
 		}
 
-		ret = zfs_mount_and_share(g_zfs, argv[1], ZFS_TYPE_DATASET);
+		/*
+		 * Dataset cloned successfully, mount/share failures are
+		 * non-fatal.
+		 */
+		(void) zfs_mount_and_share(g_zfs, argv[1], ZFS_TYPE_DATASET);
 	}
 
 	zfs_close(zhp);
@@ -1333,7 +1337,9 @@ zfs_do_create(int argc, char **argv)
 		goto error;
 	}
 
-	ret = zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET);
+	/* Dataset created successfully, mount/share failures are non-fatal */
+	ret = 0;
+	(void) zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET);
 error:
 	nvlist_free(props);
 	return (ret);
diff --git a/sys/contrib/openzfs/cmd/zinject/zinject.c b/sys/contrib/openzfs/cmd/zinject/zinject.c
index 113797c878b9..c2f646f2567d 100644
--- a/sys/contrib/openzfs/cmd/zinject/zinject.c
+++ b/sys/contrib/openzfs/cmd/zinject/zinject.c
@@ -107,6 +107,8 @@
  * 	zinject
  * 	zinject <-a | -u pool>
  * 	zinject -c <id|all>
+ * 	zinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range]
+ *	    [-T iotype] [-t type object | -b bookmark pool]
  * 	zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
  *	    [-r range] <object>
  * 	zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
@@ -132,14 +134,18 @@
  * The '-f' flag controls the frequency of errors injected, expressed as a
  * real number percentage between 0.0001 and 100.  The default is 100.
  *
- * The this form is responsible for actually injecting the handler into the
+ * The <object> form is responsible for actually injecting the handler into the
  * framework.  It takes the arguments described above, translates them to the
  * internal tuple using libzpool, and then issues an ioctl() to register the
  * handler.
  *
- * The final form can target a specific bookmark, regardless of whether a
+ * The '-b' option can target a specific bookmark, regardless of whether a
  * human-readable interface has been designed.  It allows developers to specify
  * a particular block by number.
+ *
+ * The '-E' option injects pipeline ready stage delays for the given object or
+ * bookmark. The delay is specified in milliseconds, and it supports I/O type
+ * and range filters.
  */
 
 #include <errno.h>
@@ -346,6 +352,13 @@ usage(void)
 	    "\t\tsuch that the operation takes a minimum of supplied seconds\n"
 	    "\t\tto complete.\n"
 	    "\n"
+	    "\tzinject -E <delay> [-a] [-m] [-f freq] [-l level] [-r range]\n"
+	    "\t\t[-T iotype] [-t type object | -b bookmark pool]\n"
+	    "\n"
+	    "\t\tInject pipeline ready stage delays for the given object path\n"
+	    "\t\t(data or dnode) or raw bookmark. The delay is specified in\n"
+	    "\t\tmilliseconds.\n"
+	    "\n"
 	    "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
 	    "\t\tCause the pool to stop writing blocks yet not\n"
 	    "\t\treport errors for a duration.  Simulates buggy hardware\n"
@@ -724,12 +737,15 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
 	if (quiet) {
 		(void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
 	} else {
+		boolean_t show_object = B_FALSE;
+		boolean_t show_iotype = B_FALSE;
 		(void) printf("Added handler %llu with the following "
 		    "properties:\n", (u_longlong_t)zc.zc_guid);
 		(void) printf("  pool: %s\n", pool);
 		if (record->zi_guid) {
 			(void) printf("  vdev: %llx\n",
 			    (u_longlong_t)record->zi_guid);
+			show_iotype = B_TRUE;
 		} else if (record->zi_func[0] != '\0') {
 			(void) printf("  panic function: %s\n",
 			    record->zi_func);
@@ -742,7 +758,18 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
 		} else if (record->zi_timer > 0) {
 			(void) printf(" timer: %lld ms\n",
 			    (u_longlong_t)NSEC2MSEC(record->zi_timer));
+			if (record->zi_cmd == ZINJECT_DELAY_READY) {
+				show_object = B_TRUE;
+				show_iotype = B_TRUE;
+			}
 		} else {
+			show_object = B_TRUE;
+		}
+		if (show_iotype) {
+			(void) printf("iotype: %s\n",
+			    iotype_to_str(record->zi_iotype));
+		}
+		if (show_object) {
 			(void) printf("objset: %llu\n",
 			    (u_longlong_t)record->zi_objset);
 			(void) printf("object: %llu\n",
@@ -910,6 +937,7 @@ main(int argc, char **argv)
 	int ret;
 	int flags = 0;
 	uint32_t dvas = 0;
+	hrtime_t ready_delay = -1;
 
 	if ((g_zfs = libzfs_init()) == NULL) {
 		(void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
@@ -940,7 +968,7 @@ main(int argc, char **argv)
 	}
 
 	while ((c = getopt(argc, argv,
-	    ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:")) != -1) {
+	    ":aA:b:C:d:D:E:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:")) != -1) {
 		switch (c) {
 		case 'a':
 			flags |= ZINJECT_FLUSH_ARC;
@@ -1113,6 +1141,18 @@ main(int argc, char **argv)
 		case 'u':
 			flags |= ZINJECT_UNLOAD_SPA;
 			break;
+		case 'E':
+			ready_delay = MSEC2NSEC(strtol(optarg, &end, 10));
+			if (ready_delay <= 0 || *end != '\0') {
+				(void) fprintf(stderr, "invalid delay '%s': "
+				    "must be a positive duration\n", optarg);
+				usage();
+				libzfs_fini(g_zfs);
+				return (1);
+			}
+			record.zi_cmd = ZINJECT_DELAY_READY;
+			record.zi_timer = ready_delay;
+			break;
 		case 'L':
 			if ((label = name_to_type(optarg)) == TYPE_INVAL &&
 			    !LABEL_TYPE(type)) {
@@ -1150,7 +1190,7 @@ main(int argc, char **argv)
 		 */
 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
-		    record.zi_freq > 0 || dvas != 0) {
+		    record.zi_freq > 0 || dvas != 0 || ready_delay >= 0) {
 			(void) fprintf(stderr, "cancel (-c) incompatible with "
 			    "any other options\n");
 			usage();
@@ -1186,7 +1226,7 @@ main(int argc, char **argv)
 		 */
 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
-		    dvas != 0) {
+		    dvas != 0 || ready_delay >= 0) {
 			(void) fprintf(stderr, "device (-d) incompatible with "
 			    "data error injection\n");
 			usage();
@@ -1276,13 +1316,23 @@ main(int argc, char **argv)
 			return (1);
 		}
 
-		record.zi_cmd = ZINJECT_DATA_FAULT;
+		if (record.zi_cmd == ZINJECT_UNINITIALIZED) {
+			record.zi_cmd = ZINJECT_DATA_FAULT;
+			if (!error)
+				error = EIO;
+		} else if (error != 0) {
+			(void) fprintf(stderr, "error type -e incompatible "
+			    "with delay injection\n");
+			libzfs_fini(g_zfs);
+			return (1);
+		} else {
+			record.zi_iotype = io_type;
+		}
+
 		if (translate_raw(raw, &record) != 0) {
 			libzfs_fini(g_zfs);
 			return (1);
 		}
-		if (!error)
-			error = EIO;
 	} else if (record.zi_cmd == ZINJECT_PANIC) {
 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 		    level != 0 || device != NULL || record.zi_freq > 0 ||
@@ -1410,6 +1460,13 @@ main(int argc, char **argv)
 			record.zi_dvas = dvas;
 		}
 
+		if (record.zi_cmd != ZINJECT_UNINITIALIZED && error != 0) {
+			(void) fprintf(stderr, "error type -e incompatible "
+			    "with delay injection\n");
+			libzfs_fini(g_zfs);
+			return (1);
+		}
+
 		if (error == EACCES) {
 			if (type != TYPE_DATA) {
 				(void) fprintf(stderr, "decryption errors "
@@ -1425,8 +1482,12 @@ main(int argc, char **argv)
 			 * not found.
 			 */
 			error = ECKSUM;
-		} else {
+		} else if (record.zi_cmd == ZINJECT_UNINITIALIZED) {
 			record.zi_cmd = ZINJECT_DATA_FAULT;
+			if (!error)
+				error = EIO;
+		} else {
+			record.zi_iotype = io_type;
 		}
 
 		if (translate_record(type, argv[0], range, level, &record, pool,
@@ -1434,8 +1495,6 @@ main(int argc, char **argv)
 			libzfs_fini(g_zfs);
 			return (1);
 		}
-		if (!error)
-			error = EIO;
 	}
 
 	/*
diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_iter.c b/sys/contrib/openzfs/cmd/zpool/zpool_iter.c
index 16d4fe5eb1c6..fef602736705 100644
--- a/sys/contrib/openzfs/cmd/zpool/zpool_iter.c
+++ b/sys/contrib/openzfs/cmd/zpool/zpool_iter.c
@@ -103,6 +103,7 @@ add_pool(zpool_handle_t *zhp, zpool_list_t *zlp)
 		new->zn_last_refresh = zlp->zl_last_refresh;
 		uu_avl_insert(zlp->zl_avl, new, idx);
 	} else {
+		zpool_refresh_stats_from_handle(node->zn_handle, zhp);
 		node->zn_last_refresh = zlp->zl_last_refresh;
 		zpool_close(zhp);
 		free(new);
@@ -203,31 +204,23 @@ pool_list_refresh(zpool_list_t *zlp)
 		return (navail);
 	}
 
-	/*
-	 * Search for any new pools and add them to the list. zpool_iter()
-	 * will call zpool_refresh_stats() as part of its work, so this has
-	 * the side effect of updating all active handles.
-	 */
+	/* Search for any new pools and add them to the list. */
 	(void) zpool_iter(g_zfs, add_pool_cb, zlp);
 
-	/*
-	 * Walk the list for any that weren't refreshed, and update and remove
-	 * them. It's not enough to just skip available ones, as zpool_iter()
-	 * won't update them, so they'll still appear active in our list.
-	 */
+	/* Walk the list of existing pools, and update or remove them. */
 	zpool_node_t *node, *next;
 	for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next) {
 		next = uu_avl_next(zlp->zl_avl, node);
 
 		/*
-		 * Skip any that were refreshed and are online; they're already
-		 * handled.
+		 * Skip any that were refreshed and are online; they were added
+		 * by zpool_iter() and are already up to date.
 		 */
 		if (node->zn_last_refresh == zlp->zl_last_refresh &&
 		    zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL)
 			continue;
 
-		/* Do the refresh ourselves, just in case. */
+		/* Refresh and remove if necessary. */
 		boolean_t missing;
 		zpool_refresh_stats(node->zn_handle, &missing);
 		if (missing) {
diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_main.c b/sys/contrib/openzfs/cmd/zpool/zpool_main.c
index 286336cf2730..1feec55c0e8b 100644
--- a/sys/contrib/openzfs/cmd/zpool/zpool_main.c
+++ b/sys/contrib/openzfs/cmd/zpool/zpool_main.c
@@ -6677,6 +6677,7 @@ zpool_do_iostat(int argc, char **argv)
 			if (skip) {
 				(void) fflush(stdout);
 				(void) fsleep(interval);
+				last_npools = npools;
 				continue;
 			}
 
diff --git a/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c b/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c
index 088c0108e911..222b5524669e 100644
--- a/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c
+++ b/sys/contrib/openzfs/cmd/zpool/zpool_vdev.c
@@ -270,14 +270,13 @@ is_spare(nvlist_t *config, const char *path)
  *	draid*		Virtual dRAID spare
  */
 static nvlist_t *
-make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
+make_leaf_vdev(const char *arg, boolean_t is_primary, uint64_t ashift)
 {
 	char path[MAXPATHLEN];
 	struct stat64 statbuf;
 	nvlist_t *vdev = NULL;
 	const char *type = NULL;
 	boolean_t wholedisk = B_FALSE;
-	uint64_t ashift = 0;
 	int err;
 
 	/*
@@ -381,31 +380,6 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
 		verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
 		    (uint64_t)wholedisk) == 0);
 
-	/*
-	 * Override defaults if custom properties are provided.
-	 */
-	if (props != NULL) {
-		const char *value = NULL;
-
-		if (nvlist_lookup_string(props,
-		    zpool_prop_to_name(ZPOOL_PROP_ASHIFT), &value) == 0) {
-			if (zfs_nicestrtonum(NULL, value, &ashift) != 0) {
-				(void) fprintf(stderr,
-				    gettext("ashift must be a number.\n"));
-				return (NULL);
-			}
-			if (ashift != 0 &&
-			    (ashift < ASHIFT_MIN || ashift > ASHIFT_MAX)) {
-				(void) fprintf(stderr,
-				    gettext("invalid 'ashift=%" PRIu64 "' "
-				    "property: only values between %" PRId32 " "
-				    "and %" PRId32 " are allowed.\n"),
-				    ashift, ASHIFT_MIN, ASHIFT_MAX);
-				return (NULL);
-			}
-		}
-	}
-
 	/*
 	 * If the device is known to incorrectly report its physical sector
 	 * size explicitly provide the known correct value.
@@ -1513,6 +1487,29 @@ construct_spec(nvlist_t *props, int argc, char **argv)
 	const char *type, *fulltype;
 	boolean_t is_log, is_special, is_dedup, is_spare;
 	boolean_t seen_logs;
+	uint64_t ashift = 0;
+
+	if (props != NULL) {
+		const char *value = NULL;
+
+		if (nvlist_lookup_string(props,
+		    zpool_prop_to_name(ZPOOL_PROP_ASHIFT), &value) == 0) {
+			if (zfs_nicestrtonum(NULL, value, &ashift) != 0) {
+				(void) fprintf(stderr,
+				    gettext("ashift must be a number.\n"));
+				return (NULL);
+			}
+			if (ashift != 0 &&
+			    (ashift < ASHIFT_MIN || ashift > ASHIFT_MAX)) {
+				(void) fprintf(stderr,
+				    gettext("invalid 'ashift=%" PRIu64 "' "
+				    "property: only values between %" PRId32 " "
+				    "and %" PRId32 " are allowed.\n"),
+				    ashift, ASHIFT_MIN, ASHIFT_MAX);
+				return (NULL);
+			}
+		}
+	}
 
 	top = NULL;
 	toplevels = 0;
@@ -1618,9 +1615,9 @@ construct_spec(nvlist_t *props, int argc, char **argv)
 				    children * sizeof (nvlist_t *));
 				if (child == NULL)
 					zpool_no_memory();
-				if ((nv = make_leaf_vdev(props, argv[c],
+				if ((nv = make_leaf_vdev(argv[c],
 				    !(is_log || is_special || is_dedup ||
-				    is_spare))) == NULL) {
+				    is_spare), ashift)) == NULL) {
 					for (c = 0; c < children - 1; c++)
 						nvlist_free(child[c]);
 					free(child);
@@ -1684,6 +1681,10 @@ construct_spec(nvlist_t *props, int argc, char **argv)
 					    ZPOOL_CONFIG_ALLOCATION_BIAS,
 					    VDEV_ALLOC_BIAS_DEDUP) == 0);
 				}
+				if (ashift > 0) {
+					fnvlist_add_uint64(nv,
+					    ZPOOL_CONFIG_ASHIFT, ashift);
+				}
 				if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
 					verify(nvlist_add_uint64(nv,
 					    ZPOOL_CONFIG_NPARITY,
@@ -1711,8 +1712,9 @@ construct_spec(nvlist_t *props, int argc, char **argv)
 			 * We have a device.  Pass off to make_leaf_vdev() to
 			 * construct the appropriate nvlist describing the vdev.
 			 */
-			if ((nv = make_leaf_vdev(props, argv[0], !(is_log ||
-			    is_special || is_dedup || is_spare))) == NULL)
+			if ((nv = make_leaf_vdev(argv[0], !(is_log ||
+			    is_special || is_dedup || is_spare),
+			    ashift)) == NULL)
 				goto spec_out;
 
 			verify(nvlist_add_uint64(nv,
diff --git a/sys/contrib/openzfs/config/kernel-block-device-operations.m4 b/sys/contrib/openzfs/config/kernel-block-device-operations.m4
index 4ff20b9c413d..1905340a9c7d 100644
--- a/sys/contrib/openzfs/config/kernel-block-device-operations.m4
+++ b/sys/contrib/openzfs/config/kernel-block-device-operations.m4
@@ -119,15 +119,49 @@ AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
 	])
 ])
 
+dnl #
+dnl # 6.18 API change
+dnl # block_device_operation->getgeo takes struct gendisk* as first arg
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK], [
+	ZFS_LINUX_TEST_SRC([block_device_operations_getgeo_gendisk], [
+		#include <linux/blkdev.h>
+
+		static int blk_getgeo(struct gendisk *disk, struct hd_geometry *geo)
+		{
+			(void) disk, (void) geo;
+			return (0);
+		}
+
+		static const struct block_device_operations
+		    bops __attribute__ ((unused)) = {
+			.getgeo	= blk_getgeo,
+		};
+	], [], [])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK], [
+	AC_MSG_CHECKING([whether bops->getgeo() takes gendisk as first arg])
+	ZFS_LINUX_TEST_RESULT([block_device_operations_getgeo_gendisk], [
+		AC_MSG_RESULT(yes)
+		AC_DEFINE([HAVE_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK], [1],
+			[Define if getgeo() in block_device_operations takes struct gendisk * as its first arg])
+	],[
+		AC_MSG_RESULT(no)
+	])
+])
+
 AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS], [
 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
+	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK
 ])
 
 AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS], [
 	ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
 	ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
 	ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
+	ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK
 ])
diff --git a/sys/contrib/openzfs/config/kernel-drop-inode.m4 b/sys/contrib/openzfs/config/kernel-drop-inode.m4
new file mode 100644
index 000000000000..6f2b12cadc02
--- /dev/null
+++ b/sys/contrib/openzfs/config/kernel-drop-inode.m4
@@ -0,0 +1,24 @@
+dnl #
+dnl # 6.18 API change
+dnl # - generic_drop_inode() renamed to inode_generic_drop()
+dnl # - generic_delete_inode() renamed to inode_just_drop()
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GENERIC_DROP], [
+	ZFS_LINUX_TEST_SRC([inode_generic_drop], [
+		#include <linux/fs.h>
+	],[
+		struct inode *ip = NULL;
+		inode_generic_drop(ip);
+	])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_INODE_GENERIC_DROP], [
+	AC_MSG_CHECKING([whether inode_generic_drop() exists])
+	ZFS_LINUX_TEST_RESULT([inode_generic_drop], [
+		AC_MSG_RESULT(yes)
+		AC_DEFINE(HAVE_INODE_GENERIC_DROP, 1,
+			[inode_generic_drop() exists])
+	],[
+		AC_MSG_RESULT(no)
+	])
+])
diff --git a/sys/contrib/openzfs/config/kernel-namespace.m4 b/sys/contrib/openzfs/config/kernel-namespace.m4
new file mode 100644
index 000000000000..9b0b12e4eab4
--- /dev/null
+++ b/sys/contrib/openzfs/config/kernel-namespace.m4
@@ -0,0 +1,31 @@
+dnl #
+dnl # 6.18 API change
+dnl # ns->ops->type was moved to ns->ns.ns_type (struct ns_common)
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_NS_COMMON_TYPE], [
+	ZFS_LINUX_TEST_SRC([ns_common_type], [
+		#include <linux/user_namespace.h>
+	],[
+		struct user_namespace ns;
+		ns.ns.ns_type = 0;
*** 2486 LINES SKIPPED ***