aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2025-10-25 08:14:36 +0000
committerColin Percival <cperciva@FreeBSD.org>2025-10-28 21:22:49 +0000
commit6bf158defbcb2f3c948b28394388179c7e95bd8b (patch)
tree4127b2134841705de6794b5c42e151adaf4fb154
parent470fae965fc2a458a20cbc1df2710486ae5d536d (diff)
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)
-rw-r--r--sys/contrib/openzfs/.github/ISSUE_TEMPLATE/feature_request.md2
-rwxr-xr-xsys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh11
-rw-r--r--sys/contrib/openzfs/.github/workflows/zfs-qemu.yml2
-rw-r--r--sys/contrib/openzfs/META2
-rw-r--r--sys/contrib/openzfs/cmd/zdb/zdb.c191
-rw-r--r--sys/contrib/openzfs/cmd/zfs/zfs_main.c10
-rw-r--r--sys/contrib/openzfs/cmd/zinject/zinject.c81
-rw-r--r--sys/contrib/openzfs/cmd/zpool/zpool_iter.c19
-rw-r--r--sys/contrib/openzfs/cmd/zpool/zpool_main.c1
-rw-r--r--sys/contrib/openzfs/cmd/zpool/zpool_vdev.c64
-rw-r--r--sys/contrib/openzfs/config/kernel-block-device-operations.m434
-rw-r--r--sys/contrib/openzfs/config/kernel-drop-inode.m424
-rw-r--r--sys/contrib/openzfs/config/kernel-namespace.m431
-rw-r--r--sys/contrib/openzfs/config/kernel-userns-capabilities.m479
-rw-r--r--sys/contrib/openzfs/config/kernel-writeback.m458
-rw-r--r--sys/contrib/openzfs/config/kernel-writepage_t.m426
-rw-r--r--sys/contrib/openzfs/config/kernel.m48
-rw-r--r--sys/contrib/openzfs/contrib/intel_qat/readme.md2
-rw-r--r--sys/contrib/openzfs/etc/init.d/README.md2
-rw-r--r--sys/contrib/openzfs/include/libzfs.h2
-rw-r--r--sys/contrib/openzfs/include/os/linux/kernel/linux/vfs_compat.h7
-rw-r--r--sys/contrib/openzfs/include/sys/spa.h2
-rw-r--r--sys/contrib/openzfs/include/sys/zfs_ioctl.h1
-rw-r--r--sys/contrib/openzfs/include/sys/zio.h1
-rw-r--r--sys/contrib/openzfs/lib/libspl/include/sys/uio.h1
-rw-r--r--sys/contrib/openzfs/lib/libuutil/libuutil.abi105
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs.abi172
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_config.c17
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_status.c78
-rw-r--r--sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi105
-rw-r--r--sys/contrib/openzfs/lib/libzpool/kernel.c79
-rw-r--r--sys/contrib/openzfs/man/man8/zdb.814
-rw-r--r--sys/contrib/openzfs/man/man8/zinject.814
-rw-r--r--sys/contrib/openzfs/man/man8/zpool-remove.84
-rw-r--r--sys/contrib/openzfs/module/icp/algs/sha2/sha2_generic.c41
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c3
-rw-r--r--sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c31
-rw-r--r--sys/contrib/openzfs/module/os/linux/spl/spl-zone.c19
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/abd_os.c9
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c2
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c5
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c74
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c4
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c109
-rw-r--r--sys/contrib/openzfs/module/zcommon/zfs_prop.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/arc.c17
-rw-r--r--sys/contrib/openzfs/module/zfs/mmp.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/spa_misc.c8
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_removal.c80
-rw-r--r--sys/contrib/openzfs/module/zfs/zio.c35
-rw-r--r--sys/contrib/openzfs/module/zfs/zio_inject.c38
-rw-r--r--sys/contrib/openzfs/module/zfs/zvol.c2
-rw-r--r--sys/contrib/openzfs/tests/runfiles/common.run3
-rw-r--r--sys/contrib/openzfs/tests/runfiles/sanity.run2
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/mmap_seek.c35
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am1
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh2
-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/xattr/xattr_014_pos.ksh53
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_trim.ksh7
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;
/*
@@ -382,31 +381,6 @@ make_leaf_vdev(nvlist_t *props, const char *arg, boolean_t is_primary)
(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;
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_NS_COMMON_TYPE], [
+ AC_MSG_CHECKING([whether ns_type is accessible through ns_common])
+ ZFS_LINUX_TEST_RESULT([ns_common_type], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_NS_COMMON_TYPE], 1,
+ [Define if ns_type is accessible through ns_common])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_SRC_NAMESPACE], [
+ ZFS_AC_KERNEL_SRC_NS_COMMON_TYPE
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_NAMESPACE], [
+ ZFS_AC_KERNEL_NS_COMMON_TYPE
+])
diff --git a/sys/contrib/openzfs/config/kernel-userns-capabilities.m4 b/sys/contrib/openzfs/config/kernel-userns-capabilities.m4
deleted file mode 100644
index f4e24fb1606a..000000000000
--- a/sys/contrib/openzfs/config/kernel-userns-capabilities.m4
+++ /dev/null
@@ -1,79 +0,0 @@
-dnl #
-dnl # 2.6.38 API change
-dnl # ns_capable() was introduced
-dnl #
-AC_DEFUN([ZFS_AC_KERNEL_SRC_NS_CAPABLE], [
- ZFS_LINUX_TEST_SRC([ns_capable], [
- #include <linux/capability.h>
- ],[
- ns_capable((struct user_namespace *)NULL, CAP_SYS_ADMIN);
- ])
-])
-
-AC_DEFUN([ZFS_AC_KERNEL_NS_CAPABLE], [
- AC_MSG_CHECKING([whether ns_capable exists])
- ZFS_LINUX_TEST_RESULT([ns_capable], [
- AC_MSG_RESULT(yes)
- ],[
- ZFS_LINUX_TEST_ERROR([ns_capable()])
- ])
-])
-
-dnl #
-dnl # 2.6.39 API change
-dnl # struct user_namespace was added to struct cred_t as cred->user_ns member
-dnl #
-AC_DEFUN([ZFS_AC_KERNEL_SRC_CRED_USER_NS], [
- ZFS_LINUX_TEST_SRC([cred_user_ns], [
- #include <linux/cred.h>
- ],[
- struct cred cr;
- cr.user_ns = (struct user_namespace *)NULL;
- ])
-])
-
-AC_DEFUN([ZFS_AC_KERNEL_CRED_USER_NS], [
- AC_MSG_CHECKING([whether cred_t->user_ns exists])
- ZFS_LINUX_TEST_RESULT([cred_user_ns], [
- AC_MSG_RESULT(yes)
- ],[
- ZFS_LINUX_TEST_ERROR([cred_t->user_ns()])
- ])
-])
-
-dnl #
-dnl # 3.4 API change
-dnl # kuid_has_mapping() and kgid_has_mapping() were added to distinguish
-dnl # between internal kernel uids/gids and user namespace uids/gids.
-dnl #
-AC_DEFUN([ZFS_AC_KERNEL_SRC_KUID_HAS_MAPPING], [
- ZFS_LINUX_TEST_SRC([kuid_has_mapping], [
- #include <linux/uidgid.h>
- ],[
- kuid_has_mapping((struct user_namespace *)NULL, KUIDT_INIT(0));
- kgid_has_mapping((struct user_namespace *)NULL, KGIDT_INIT(0));
- ])
-])
-
-AC_DEFUN([ZFS_AC_KERNEL_KUID_HAS_MAPPING], [
- AC_MSG_CHECKING([whether kuid_has_mapping/kgid_has_mapping exist])
- ZFS_LINUX_TEST_RESULT([kuid_has_mapping], [
- AC_MSG_RESULT(yes)
- ],[
- ZFS_LINUX_TEST_ERROR([kuid_has_mapping()])
- ])
-])
-
-AC_DEFUN([ZFS_AC_KERNEL_SRC_USERNS_CAPABILITIES], [
- ZFS_AC_KERNEL_SRC_NS_CAPABLE
- ZFS_AC_KERNEL_SRC_HAS_CAPABILITY
- ZFS_AC_KERNEL_SRC_CRED_USER_NS
- ZFS_AC_KERNEL_SRC_KUID_HAS_MAPPING
-])
-
-AC_DEFUN([ZFS_AC_KERNEL_USERNS_CAPABILITIES], [
- ZFS_AC_KERNEL_NS_CAPABLE
- ZFS_AC_KERNEL_HAS_CAPABILITY
- ZFS_AC_KERNEL_CRED_USER_NS
- ZFS_AC_KERNEL_KUID_HAS_MAPPING
-])
diff --git a/sys/contrib/openzfs/config/kernel-writeback.m4 b/sys/contrib/openzfs/config/kernel-writeback.m4
new file mode 100644
index 000000000000..334d65ef84b6
--- /dev/null
+++ b/sys/contrib/openzfs/config/kernel-writeback.m4
@@ -0,0 +1,58 @@
+AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEPAGE_T], [
+ dnl #
+ dnl # 6.3 API change
+ dnl # The writepage_t function type now has its first argument as
+ dnl # struct folio* instead of struct page*
+ dnl #
+ ZFS_LINUX_TEST_SRC([writepage_t_folio], [
+ #include <linux/writeback.h>
+ static int putpage(struct folio *folio,
+ struct writeback_control *wbc, void *data)
+ { return 0; }
+ writepage_t func = putpage;
+ ],[])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_WRITEPAGE_T], [
+ AC_MSG_CHECKING([whether int (*writepage_t)() takes struct folio*])
+ ZFS_LINUX_TEST_RESULT([writepage_t_folio], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_WRITEPAGE_T_FOLIO, 1,
+ [int (*writepage_t)() takes struct folio*])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITE_CACHE_PAGES], [
+ dnl #
+ dnl # 6.18 API change
+ dnl # write_cache_pages() has been removed.
+ dnl #
+ ZFS_LINUX_TEST_SRC([write_cache_pages], [
+ #include <linux/writeback.h>
+ ], [
+ (void) write_cache_pages(NULL, NULL, NULL, NULL);
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_WRITE_CACHE_PAGES], [
+ AC_MSG_CHECKING([whether write_cache_pages() is available])
+ ZFS_LINUX_TEST_RESULT([write_cache_pages], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_WRITE_CACHE_PAGES, 1,
+ [write_cache_pages() is available])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEBACK], [
+ ZFS_AC_KERNEL_SRC_WRITEPAGE_T
+ ZFS_AC_KERNEL_SRC_WRITE_CACHE_PAGES
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_WRITEBACK], [
+ ZFS_AC_KERNEL_WRITEPAGE_T
+ ZFS_AC_KERNEL_WRITE_CACHE_PAGES
+])
diff --git a/sys/contrib/openzfs/config/kernel-writepage_t.m4 b/sys/contrib/openzfs/config/kernel-writepage_t.m4
deleted file mode 100644
index a82cf370c9d4..000000000000
--- a/sys/contrib/openzfs/config/kernel-writepage_t.m4
+++ /dev/null
@@ -1,26 +0,0 @@
-AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEPAGE_T], [
- dnl #
- dnl # 6.3 API change
- dnl # The writepage_t function type now has its first argument as
- dnl # struct folio* instead of struct page*
- dnl #
- ZFS_LINUX_TEST_SRC([writepage_t_folio], [
- #include <linux/writeback.h>
- static int putpage(struct folio *folio,
- struct writeback_control *wbc, void *data)
- { return 0; }
- writepage_t func = putpage;
- ],[])
-])
-
-AC_DEFUN([ZFS_AC_KERNEL_WRITEPAGE_T], [
- AC_MSG_CHECKING([whether int (*writepage_t)() takes struct folio*])
- ZFS_LINUX_TEST_RESULT([writepage_t_folio], [
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_WRITEPAGE_T_FOLIO, 1,
- [int (*writepage_t)() takes struct folio*])
- ],[
- AC_MSG_RESULT(no)
- ])
-])
-
diff --git a/sys/contrib/openzfs/config/kernel.m4 b/sys/contrib/openzfs/config/kernel.m4
index 35819e4d68c5..40b7de739882 100644
--- a/sys/contrib/openzfs/config/kernel.m4
+++ b/sys/contrib/openzfs/config/kernel.m4
@@ -121,7 +121,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
ZFS_AC_KERNEL_SRC_IDMAP_NO_USERNS
ZFS_AC_KERNEL_SRC_IATTR_VFSID
- ZFS_AC_KERNEL_SRC_WRITEPAGE_T
+ ZFS_AC_KERNEL_SRC_WRITEBACK
ZFS_AC_KERNEL_SRC_RECLAIMED
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ
@@ -136,6 +136,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_TIMER
ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_WB_ERR
ZFS_AC_KERNEL_SRC_SOPS_FREE_INODE
+ ZFS_AC_KERNEL_SRC_NAMESPACE
+ ZFS_AC_KERNEL_SRC_INODE_GENERIC_DROP
case "$host_cpu" in
powerpc*)
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
@@ -240,7 +242,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_IDMAP_MNT_API
ZFS_AC_KERNEL_IDMAP_NO_USERNS
ZFS_AC_KERNEL_IATTR_VFSID
- ZFS_AC_KERNEL_WRITEPAGE_T
+ ZFS_AC_KERNEL_WRITEBACK
ZFS_AC_KERNEL_RECLAIMED
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ
@@ -256,6 +258,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_TIMER
ZFS_AC_KERNEL_SUPER_BLOCK_S_WB_ERR
ZFS_AC_KERNEL_SOPS_FREE_INODE
+ ZFS_AC_KERNEL_NAMESPACE
+ ZFS_AC_KERNEL_INODE_GENERIC_DROP
case "$host_cpu" in
powerpc*)
ZFS_AC_KERNEL_CPU_HAS_FEATURE
diff --git a/sys/contrib/openzfs/contrib/intel_qat/readme.md b/sys/contrib/openzfs/contrib/intel_qat/readme.md
index 7e45d395bb80..04c299b6404c 100644
--- a/sys/contrib/openzfs/contrib/intel_qat/readme.md
+++ b/sys/contrib/openzfs/contrib/intel_qat/readme.md
@@ -8,7 +8,7 @@ This contrib contains community compatibility patches to get Intel QAT working o
These patches are based on the following Intel QAT version:
[1.7.l.4.10.0-00014](https://01.org/sites/default/files/downloads/qat1.7.l.4.10.0-00014.tar.gz)
-When using QAT with above kernels versions, the following patches needs to be applied using:
+When using QAT with the above kernel versions, the following patches need to be applied using:
patch -p1 < _$PATCH_
_Where $PATCH refers to the path of the patch in question_
diff --git a/sys/contrib/openzfs/etc/init.d/README.md b/sys/contrib/openzfs/etc/init.d/README.md
index da780fdc1222..3852dd9a6b2e 100644
--- a/sys/contrib/openzfs/etc/init.d/README.md
+++ b/sys/contrib/openzfs/etc/init.d/README.md
@@ -1,5 +1,5 @@
DESCRIPTION
- These script were written with the primary intention of being portable and
+ These scripts were written with the primary intention of being portable and
usable on as many systems as possible.
This is, in practice, usually not possible. But the intention is there.
diff --git a/sys/contrib/openzfs/include/libzfs.h b/sys/contrib/openzfs/include/libzfs.h
index 3fcdc176a621..14930fb90622 100644
--- a/sys/contrib/openzfs/include/libzfs.h
+++ b/sys/contrib/openzfs/include/libzfs.h
@@ -479,6 +479,8 @@ _LIBZFS_H zpool_status_t zpool_import_status(nvlist_t *, const char **,
_LIBZFS_H nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
_LIBZFS_H nvlist_t *zpool_get_features(zpool_handle_t *);
_LIBZFS_H int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
+_LIBZFS_H void zpool_refresh_stats_from_handle(zpool_handle_t *,
+ zpool_handle_t *);
_LIBZFS_H int zpool_get_errlog(zpool_handle_t *, nvlist_t **);
_LIBZFS_H void zpool_add_propname(zpool_handle_t *, const char *);
diff --git a/sys/contrib/openzfs/include/os/linux/kernel/linux/vfs_compat.h b/sys/contrib/openzfs/include/os/linux/kernel/linux/vfs_compat.h
index cbf14e28371f..d9dc904bc322 100644
--- a/sys/contrib/openzfs/include/os/linux/kernel/linux/vfs_compat.h
+++ b/sys/contrib/openzfs/include/os/linux/kernel/linux/vfs_compat.h
@@ -23,6 +23,7 @@
/*
* Copyright (C) 2011 Lawrence Livermore National Security, LLC.
* Copyright (C) 2015 Jörg Thalheim.
+ * Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
*/
#ifndef _ZFS_VFS_H
@@ -262,4 +263,10 @@ zpl_is_32bit_api(void)
#define zpl_generic_fillattr(user_ns, ip, sp) generic_fillattr(ip, sp)
#endif
+#ifdef HAVE_INODE_GENERIC_DROP
+/* 6.18 API change. These were renamed, alias the old names to the new. */
+#define generic_delete_inode(ip) inode_just_drop(ip)
+#define generic_drop_inode(ip) inode_generic_drop(ip)
+#endif
+
#endif /* _ZFS_VFS_H */
diff --git a/sys/contrib/openzfs/include/sys/spa.h b/sys/contrib/openzfs/include/sys/spa.h
index 39971827073f..f172f2af6f07 100644
--- a/sys/contrib/openzfs/include/sys/spa.h
+++ b/sys/contrib/openzfs/include/sys/spa.h
@@ -1030,7 +1030,7 @@ extern void spa_import_progress_set_notes_nolog(spa_t *spa,
extern int spa_config_tryenter(spa_t *spa, int locks, const void *tag,
krw_t rw);
extern void spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw);
-extern void spa_config_enter_mmp(spa_t *spa, int locks, const void *tag,
+extern void spa_config_enter_priority(spa_t *spa, int locks, const void *tag,
krw_t rw);
extern void spa_config_exit(spa_t *spa, int locks, const void *tag);
extern int spa_config_held(spa_t *spa, int locks, krw_t rw);
diff --git a/sys/contrib/openzfs/include/sys/zfs_ioctl.h b/sys/contrib/openzfs/include/sys/zfs_ioctl.h
index 8174242abdac..cfe11f43bb8e 100644
--- a/sys/contrib/openzfs/include/sys/zfs_ioctl.h
+++ b/sys/contrib/openzfs/include/sys/zfs_ioctl.h
@@ -455,6 +455,7 @@ typedef enum zinject_type {
ZINJECT_DECRYPT_FAULT,
ZINJECT_DELAY_IMPORT,
ZINJECT_DELAY_EXPORT,
+ ZINJECT_DELAY_READY,
} zinject_type_t;
typedef enum zinject_iotype {
diff --git a/sys/contrib/openzfs/include/sys/zio.h b/sys/contrib/openzfs/include/sys/zio.h
index a8acb83b4c2f..acb0a03a36b2 100644
--- a/sys/contrib/openzfs/include/sys/zio.h
+++ b/sys/contrib/openzfs/include/sys/zio.h
@@ -718,6 +718,7 @@ extern void zio_handle_ignored_writes(zio_t *zio);
extern hrtime_t zio_handle_io_delay(zio_t *zio);
extern void zio_handle_import_delay(spa_t *spa, hrtime_t elapsed);
extern void zio_handle_export_delay(spa_t *spa, hrtime_t elapsed);
+extern hrtime_t zio_handle_ready_delay(zio_t *zio);
/*
* Checksum ereport functions
diff --git a/sys/contrib/openzfs/lib/libspl/include/sys/uio.h b/sys/contrib/openzfs/lib/libspl/include/sys/uio.h
index 93aa4984d734..9ada482be000 100644
--- a/sys/contrib/openzfs/lib/libspl/include/sys/uio.h
+++ b/sys/contrib/openzfs/lib/libspl/include/sys/uio.h
@@ -41,6 +41,7 @@
#ifndef _LIBSPL_SYS_UIO_H
#define _LIBSPL_SYS_UIO_H
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include_next <sys/uio.h>
diff --git a/sys/contrib/openzfs/lib/libuutil/libuutil.abi b/sys/contrib/openzfs/lib/libuutil/libuutil.abi
index 6c736c61e4a5..2a740afa07ca 100644
--- a/sys/contrib/openzfs/lib/libuutil/libuutil.abi
+++ b/sys/contrib/openzfs/lib/libuutil/libuutil.abi
@@ -616,6 +616,7 @@
<array-type-def dimensions='1' type-id='de572c22' size-in-bits='1472' id='6d3c2f42'>
<subrange length='23' type-id='7359adad' id='fdd0f594'/>
</array-type-def>
+ <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/>
<array-type-def dimensions='1' type-id='3a47d82b' size-in-bits='256' id='a133ec23'>
<subrange length='4' type-id='7359adad' id='16fe7105'/>
</array-type-def>
@@ -1020,13 +1021,6 @@
<array-type-def dimensions='1' type-id='03085adc' size-in-bits='192' id='083f8d58'>
<subrange length='3' type-id='7359adad' id='56f209d2'/>
</array-type-def>
- <array-type-def dimensions='1' type-id='d315442e' size-in-bits='16' id='811205dc'>
- <subrange length='1' type-id='7359adad' id='52f813b4'/>
- </array-type-def>
- <array-type-def dimensions='1' type-id='d3130597' size-in-bits='768' id='f63f23b9'>
- <subrange length='12' type-id='7359adad' id='84827bdc'/>
- </array-type-def>
- <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/>
<class-decl name='mnttab' size-in-bits='256' is-struct='yes' visibility='default' id='1b055409'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='mnt_special' type-id='26a90f95' visibility='default'/>
@@ -1061,93 +1055,6 @@
<var-decl name='mnt_minor' type-id='3502e3ff' visibility='default'/>
</data-member>
</class-decl>
- <typedef-decl name='__u16' type-id='8efea9e5' id='d315442e'/>
- <typedef-decl name='__s32' type-id='95e97e5e' id='3158a266'/>
- <typedef-decl name='__u32' type-id='f0981eeb' id='3f1a6b60'/>
- <typedef-decl name='__s64' type-id='1eb56b1e' id='49659421'/>
- <typedef-decl name='__u64' type-id='3a47d82b' id='d3130597'/>
- <class-decl name='statx_timestamp' size-in-bits='128' is-struct='yes' visibility='default' id='94101016'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='tv_sec' type-id='49659421' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='tv_nsec' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='96'>
- <var-decl name='__reserved' type-id='3158a266' visibility='default'/>
- </data-member>
- </class-decl>
- <class-decl name='statx' size-in-bits='2048' is-struct='yes' visibility='default' id='720b04c5'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='stx_mask' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='32'>
- <var-decl name='stx_blksize' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='stx_attributes' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='stx_nlink' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='160'>
- <var-decl name='stx_uid' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='192'>
- <var-decl name='stx_gid' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='224'>
- <var-decl name='stx_mode' type-id='d315442e' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='240'>
- <var-decl name='__spare0' type-id='811205dc' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='256'>
- <var-decl name='stx_ino' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='320'>
- <var-decl name='stx_size' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='384'>
- <var-decl name='stx_blocks' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='448'>
- <var-decl name='stx_attributes_mask' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='512'>
- <var-decl name='stx_atime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='640'>
- <var-decl name='stx_btime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='768'>
- <var-decl name='stx_ctime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='896'>
- <var-decl name='stx_mtime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1024'>
- <var-decl name='stx_rdev_major' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1056'>
- <var-decl name='stx_rdev_minor' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1088'>
- <var-decl name='stx_dev_major' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1120'>
- <var-decl name='stx_dev_minor' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1152'>
- <var-decl name='stx_mnt_id' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1216'>
- <var-decl name='__spare2' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1280'>
- <var-decl name='__spare3' type-id='f63f23b9' visibility='default'/>
- </data-member>
- </class-decl>
<class-decl name='mntent' size-in-bits='320' is-struct='yes' visibility='default' id='56fe4a37'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='mnt_fsname' type-id='26a90f95' visibility='default'/>
@@ -1237,8 +1144,6 @@
<pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/>
<pointer-type-def type-id='0bbec9cd' size-in-bits='64' id='62f7a03d'/>
<qualified-type-def type-id='62f7a03d' restrict='yes' id='f1cadedf'/>
- <pointer-type-def type-id='720b04c5' size-in-bits='64' id='936b8e35'/>
- <qualified-type-def type-id='936b8e35' restrict='yes' id='31d265b7'/>
<function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='e75a27e9'/>
<parameter type-id='3cad23cd'/>
@@ -1254,14 +1159,6 @@
<parameter type-id='95e97e5e'/>
<return type-id='26a90f95'/>
</function-decl>
- <function-decl name='statx' visibility='default' binding='global' size-in-bits='64'>
- <parameter type-id='95e97e5e'/>
- <parameter type-id='9d26089a'/>
- <parameter type-id='95e97e5e'/>
- <parameter type-id='f0981eeb'/>
- <parameter type-id='31d265b7'/>
- <return type-id='95e97e5e'/>
- </function-decl>
<function-decl name='__fprintf_chk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='e75a27e9'/>
<parameter type-id='95e97e5e'/>
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs.abi b/sys/contrib/openzfs/lib/libzfs/libzfs.abi
index 184ea4a55b43..f988d27a286a 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs.abi
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs.abi
@@ -571,6 +571,7 @@
<elf-symbol name='zpool_props_refresh' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_read_label' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_refresh_stats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zpool_refresh_stats_from_handle' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_reguid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_reopen_one' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_scan' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -641,7 +642,7 @@
<elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='spa_feature_table' size='2632' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
- <elf-symbol name='zfs_deleg_perm_tab' size='528' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='zfs_deleg_perm_tab' size='544' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_max_dataset_nesting' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_userquota_prop_prefixes' size='96' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -1458,103 +1459,8 @@
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libspl/os/linux/getmntany.c' language='LANG_C99'>
- <array-type-def dimensions='1' type-id='d315442e' size-in-bits='16' id='811205dc'>
- <subrange length='1' type-id='7359adad' id='52f813b4'/>
- </array-type-def>
- <array-type-def dimensions='1' type-id='d3130597' size-in-bits='768' id='f63f23b9'>
- <subrange length='12' type-id='7359adad' id='84827bdc'/>
- </array-type-def>
- <typedef-decl name='__u16' type-id='8efea9e5' id='d315442e'/>
- <typedef-decl name='__s32' type-id='95e97e5e' id='3158a266'/>
- <typedef-decl name='__u32' type-id='f0981eeb' id='3f1a6b60'/>
- <typedef-decl name='__s64' type-id='1eb56b1e' id='49659421'/>
- <typedef-decl name='__u64' type-id='3a47d82b' id='d3130597'/>
- <class-decl name='statx_timestamp' size-in-bits='128' is-struct='yes' visibility='default' id='94101016'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='tv_sec' type-id='49659421' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='tv_nsec' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='96'>
- <var-decl name='__reserved' type-id='3158a266' visibility='default'/>
- </data-member>
- </class-decl>
- <class-decl name='statx' size-in-bits='2048' is-struct='yes' visibility='default' id='720b04c5'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='stx_mask' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='32'>
- <var-decl name='stx_blksize' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='stx_attributes' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='stx_nlink' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='160'>
- <var-decl name='stx_uid' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='192'>
- <var-decl name='stx_gid' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='224'>
- <var-decl name='stx_mode' type-id='d315442e' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='240'>
- <var-decl name='__spare0' type-id='811205dc' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='256'>
- <var-decl name='stx_ino' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='320'>
- <var-decl name='stx_size' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='384'>
- <var-decl name='stx_blocks' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='448'>
- <var-decl name='stx_attributes_mask' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='512'>
- <var-decl name='stx_atime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='640'>
- <var-decl name='stx_btime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='768'>
- <var-decl name='stx_ctime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='896'>
- <var-decl name='stx_mtime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1024'>
- <var-decl name='stx_rdev_major' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1056'>
- <var-decl name='stx_rdev_minor' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1088'>
- <var-decl name='stx_dev_major' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1120'>
- <var-decl name='stx_dev_minor' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1152'>
- <var-decl name='stx_mnt_id' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1216'>
- <var-decl name='__spare2' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1280'>
- <var-decl name='__spare3' type-id='f63f23b9' visibility='default'/>
- </data-member>
- </class-decl>
<pointer-type-def type-id='56fe4a37' size-in-bits='64' id='b6b61d2f'/>
<qualified-type-def type-id='b6b61d2f' restrict='yes' id='3cad23cd'/>
- <pointer-type-def type-id='720b04c5' size-in-bits='64' id='936b8e35'/>
- <qualified-type-def type-id='936b8e35' restrict='yes' id='31d265b7'/>
<function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='e75a27e9'/>
<parameter type-id='3cad23cd'/>
@@ -1566,14 +1472,6 @@
<parameter type-id='822cd80b'/>
<return type-id='95e97e5e'/>
</function-decl>
- <function-decl name='statx' visibility='default' binding='global' size-in-bits='64'>
- <parameter type-id='95e97e5e'/>
- <parameter type-id='9d26089a'/>
- <parameter type-id='95e97e5e'/>
- <parameter type-id='f0981eeb'/>
- <parameter type-id='31d265b7'/>
- <return type-id='95e97e5e'/>
- </function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libspl/timestamp.c' language='LANG_C99'>
<typedef-decl name='nl_item' type-id='95e97e5e' id='03b79a94'/>
@@ -3194,6 +3092,10 @@
<parameter type-id='dace003f'/>
<return type-id='80f4b756'/>
</function-decl>
+ <function-decl name='fnvlist_dup' visibility='default' binding='global' size-in-bits='64'>
+ <parameter type-id='22cce67b'/>
+ <return type-id='5ce45b60'/>
+ </function-decl>
<function-decl name='fnvpair_value_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='3fa542f0'/>
<return type-id='5ce45b60'/>
@@ -3238,6 +3140,11 @@
<parameter type-id='37e3bd22' name='missing'/>
<return type-id='95e97e5e'/>
</function-decl>
+ <function-decl name='zpool_refresh_stats_from_handle' mangled-name='zpool_refresh_stats_from_handle' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_refresh_stats_from_handle'>
+ <parameter type-id='4c81de99' name='dzhp'/>
+ <parameter type-id='4c81de99' name='szhp'/>
+ <return type-id='48b5725f'/>
+ </function-decl>
<function-decl name='zpool_skip_pool' mangled-name='zpool_skip_pool' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_skip_pool'>
<parameter type-id='80f4b756' name='poolname'/>
<return type-id='c19b74c3'/>
@@ -9398,10 +9305,6 @@
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
</function-decl>
- <function-decl name='fnvlist_dup' visibility='default' binding='global' size-in-bits='64'>
- <parameter type-id='22cce67b'/>
- <return type-id='5ce45b60'/>
- </function-decl>
<function-decl name='spl_pagesize' mangled-name='spl_pagesize' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='spl_pagesize'>
<return type-id='b59d7dce'/>
</function-decl>
@@ -9774,8 +9677,8 @@
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='module/zcommon/zfs_deleg.c' language='LANG_C99'>
- <array-type-def dimensions='1' type-id='fa1870fd' size-in-bits='4224' id='55e705e7'>
- <subrange length='33' type-id='7359adad' id='6a5934df'/>
+ <array-type-def dimensions='1' type-id='fa1870fd' size-in-bits='4352' id='55f84f08'>
+ <subrange length='34' type-id='7359adad' id='6a6a7e00'/>
</array-type-def>
<array-type-def dimensions='1' type-id='fa1870fd' size-in-bits='infinite' id='7c00e69d'>
<subrange length='infinite' id='031f2035'/>
@@ -9805,30 +9708,31 @@
<enumerator name='ZFS_DELEG_NOTE_PROMOTE' value='5'/>
<enumerator name='ZFS_DELEG_NOTE_RENAME' value='6'/>
<enumerator name='ZFS_DELEG_NOTE_SEND' value='7'/>
- <enumerator name='ZFS_DELEG_NOTE_RECEIVE' value='8'/>
- <enumerator name='ZFS_DELEG_NOTE_ALLOW' value='9'/>
- <enumerator name='ZFS_DELEG_NOTE_USERPROP' value='10'/>
- <enumerator name='ZFS_DELEG_NOTE_MOUNT' value='11'/>
- <enumerator name='ZFS_DELEG_NOTE_SHARE' value='12'/>
- <enumerator name='ZFS_DELEG_NOTE_USERQUOTA' value='13'/>
- <enumerator name='ZFS_DELEG_NOTE_GROUPQUOTA' value='14'/>
- <enumerator name='ZFS_DELEG_NOTE_USERUSED' value='15'/>
- <enumerator name='ZFS_DELEG_NOTE_GROUPUSED' value='16'/>
- <enumerator name='ZFS_DELEG_NOTE_USEROBJQUOTA' value='17'/>
- <enumerator name='ZFS_DELEG_NOTE_GROUPOBJQUOTA' value='18'/>
- <enumerator name='ZFS_DELEG_NOTE_USEROBJUSED' value='19'/>
- <enumerator name='ZFS_DELEG_NOTE_GROUPOBJUSED' value='20'/>
- <enumerator name='ZFS_DELEG_NOTE_HOLD' value='21'/>
- <enumerator name='ZFS_DELEG_NOTE_RELEASE' value='22'/>
- <enumerator name='ZFS_DELEG_NOTE_DIFF' value='23'/>
- <enumerator name='ZFS_DELEG_NOTE_BOOKMARK' value='24'/>
- <enumerator name='ZFS_DELEG_NOTE_LOAD_KEY' value='25'/>
- <enumerator name='ZFS_DELEG_NOTE_CHANGE_KEY' value='26'/>
- <enumerator name='ZFS_DELEG_NOTE_PROJECTUSED' value='27'/>
- <enumerator name='ZFS_DELEG_NOTE_PROJECTQUOTA' value='28'/>
- <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJUSED' value='29'/>
- <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJQUOTA' value='30'/>
- <enumerator name='ZFS_DELEG_NOTE_NONE' value='31'/>
+ <enumerator name='ZFS_DELEG_NOTE_SEND_RAW' value='8'/>
+ <enumerator name='ZFS_DELEG_NOTE_RECEIVE' value='9'/>
+ <enumerator name='ZFS_DELEG_NOTE_ALLOW' value='10'/>
+ <enumerator name='ZFS_DELEG_NOTE_USERPROP' value='11'/>
+ <enumerator name='ZFS_DELEG_NOTE_MOUNT' value='12'/>
+ <enumerator name='ZFS_DELEG_NOTE_SHARE' value='13'/>
+ <enumerator name='ZFS_DELEG_NOTE_USERQUOTA' value='14'/>
+ <enumerator name='ZFS_DELEG_NOTE_GROUPQUOTA' value='15'/>
+ <enumerator name='ZFS_DELEG_NOTE_USERUSED' value='16'/>
+ <enumerator name='ZFS_DELEG_NOTE_GROUPUSED' value='17'/>
+ <enumerator name='ZFS_DELEG_NOTE_USEROBJQUOTA' value='18'/>
+ <enumerator name='ZFS_DELEG_NOTE_GROUPOBJQUOTA' value='19'/>
+ <enumerator name='ZFS_DELEG_NOTE_USEROBJUSED' value='20'/>
+ <enumerator name='ZFS_DELEG_NOTE_GROUPOBJUSED' value='21'/>
+ <enumerator name='ZFS_DELEG_NOTE_HOLD' value='22'/>
+ <enumerator name='ZFS_DELEG_NOTE_RELEASE' value='23'/>
+ <enumerator name='ZFS_DELEG_NOTE_DIFF' value='24'/>
+ <enumerator name='ZFS_DELEG_NOTE_BOOKMARK' value='25'/>
+ <enumerator name='ZFS_DELEG_NOTE_LOAD_KEY' value='26'/>
+ <enumerator name='ZFS_DELEG_NOTE_CHANGE_KEY' value='27'/>
+ <enumerator name='ZFS_DELEG_NOTE_PROJECTUSED' value='28'/>
+ <enumerator name='ZFS_DELEG_NOTE_PROJECTQUOTA' value='29'/>
+ <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJUSED' value='30'/>
+ <enumerator name='ZFS_DELEG_NOTE_PROJECTOBJQUOTA' value='31'/>
+ <enumerator name='ZFS_DELEG_NOTE_NONE' value='32'/>
</enum-decl>
<typedef-decl name='zfs_deleg_note_t' type-id='729d4547' id='4613c173'/>
<class-decl name='zfs_deleg_perm_tab' size-in-bits='128' is-struct='yes' visibility='default' id='5aa05c1f'>
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_config.c b/sys/contrib/openzfs/lib/libzfs/libzfs_config.c
index 0d2102191389..9d704e4303ff 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_config.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_config.c
@@ -308,6 +308,23 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
}
/*
+ * Copies the pool config and state from szhp to dzhp. szhp and dzhp must
+ * represent the same pool. Used by pool_list_refresh() to avoid another
+ * round-trip into the kernel to get stats already collected earlier in the
+ * function.
+ */
+void
+zpool_refresh_stats_from_handle(zpool_handle_t *dzhp, zpool_handle_t *szhp)
+{
+ VERIFY0(strcmp(dzhp->zpool_name, szhp->zpool_name));
+ nvlist_free(dzhp->zpool_old_config);
+ dzhp->zpool_old_config = dzhp->zpool_config;
+ dzhp->zpool_config = fnvlist_dup(szhp->zpool_config);
+ dzhp->zpool_config_size = szhp->zpool_config_size;
+ dzhp->zpool_state = szhp->zpool_state;
+}
+
+/*
* The following environment variables are undocumented
* and should be used for testing purposes only:
*
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_status.c b/sys/contrib/openzfs/lib/libzfs/libzfs_status.c
index bdddefb92165..a589ca6896f0 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_status.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_status.c
@@ -98,57 +98,57 @@ static const char *const zfs_msgid_table[] = {
#define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
static int
-vdev_missing(vdev_stat_t *vs, uint_t vsc)
+vdev_missing(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- (void) vsc;
+ (void) vsc, (void) arg;
return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
vs->vs_aux == VDEV_AUX_OPEN_FAILED);
}
static int
-vdev_faulted(vdev_stat_t *vs, uint_t vsc)
+vdev_faulted(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- (void) vsc;
+ (void) vsc, (void) arg;
return (vs->vs_state == VDEV_STATE_FAULTED);
}
static int
-vdev_errors(vdev_stat_t *vs, uint_t vsc)
+vdev_errors(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- (void) vsc;
+ (void) vsc, (void) arg;
return (vs->vs_state == VDEV_STATE_DEGRADED ||
vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
vs->vs_checksum_errors != 0);
}
static int
-vdev_broken(vdev_stat_t *vs, uint_t vsc)
+vdev_broken(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- (void) vsc;
+ (void) vsc, (void) arg;
return (vs->vs_state == VDEV_STATE_CANT_OPEN);
}
static int
-vdev_offlined(vdev_stat_t *vs, uint_t vsc)
+vdev_offlined(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- (void) vsc;
+ (void) vsc, (void) arg;
return (vs->vs_state == VDEV_STATE_OFFLINE);
}
static int
-vdev_removed(vdev_stat_t *vs, uint_t vsc)
+vdev_removed(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- (void) vsc;
+ (void) vsc, (void) arg;
return (vs->vs_state == VDEV_STATE_REMOVED);
}
static int
-vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
+vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc, void *arg)
{
- if (getenv("ZPOOL_STATUS_NON_NATIVE_ASHIFT_IGNORE") != NULL)
- return (0);
+ uint64_t ashift = *(uint64_t *)arg;
return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
+ (ashift == 0 || vs->vs_configured_ashift < ashift) &&
vs->vs_configured_ashift < vs->vs_physical_ashift);
}
@@ -156,8 +156,8 @@ vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
* Detect if any leaf devices that have seen errors or could not be opened.
*/
static boolean_t
-find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
- boolean_t ignore_replacing)
+find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t, void *),
+ void *arg, boolean_t ignore_replacing)
{
nvlist_t **child;
uint_t c, children;
@@ -177,14 +177,16 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
&children) == 0) {
- for (c = 0; c < children; c++)
- if (find_vdev_problem(child[c], func, ignore_replacing))
+ for (c = 0; c < children; c++) {
+ if (find_vdev_problem(child[c], func, arg,
+ ignore_replacing))
return (B_TRUE);
+ }
} else {
uint_t vsc;
vdev_stat_t *vs = (vdev_stat_t *)fnvlist_lookup_uint64_array(
vdev, ZPOOL_CONFIG_VDEV_STATS, &vsc);
- if (func(vs, vsc) != 0)
+ if (func(vs, vsc, arg) != 0)
return (B_TRUE);
}
@@ -193,9 +195,11 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
*/
if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
&children) == 0) {
- for (c = 0; c < children; c++)
- if (find_vdev_problem(child[c], func, ignore_replacing))
+ for (c = 0; c < children; c++) {
+ if (find_vdev_problem(child[c], func, arg,
+ ignore_replacing))
return (B_TRUE);
+ }
}
return (B_FALSE);
@@ -220,7 +224,7 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
*/
static zpool_status_t
check_status(nvlist_t *config, boolean_t isimport,
- zpool_errata_t *erratap, const char *compat)
+ zpool_errata_t *erratap, const char *compat, uint64_t ashift)
{
pool_scan_stat_t *ps = NULL;
uint_t vsc, psc;
@@ -371,15 +375,15 @@ check_status(nvlist_t *config, boolean_t isimport,
* Bad devices in non-replicated config.
*/
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
- find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
+ find_vdev_problem(nvroot, vdev_faulted, NULL, B_TRUE))
return (ZPOOL_STATUS_FAULTED_DEV_NR);
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
- find_vdev_problem(nvroot, vdev_missing, B_TRUE))
+ find_vdev_problem(nvroot, vdev_missing, NULL, B_TRUE))
return (ZPOOL_STATUS_MISSING_DEV_NR);
if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
- find_vdev_problem(nvroot, vdev_broken, B_TRUE))
+ find_vdev_problem(nvroot, vdev_broken, NULL, B_TRUE))
return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
/*
@@ -402,35 +406,37 @@ check_status(nvlist_t *config, boolean_t isimport,
/*
* Missing devices in a replicated config.
*/
- if (find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
+ if (find_vdev_problem(nvroot, vdev_faulted, NULL, B_TRUE))
return (ZPOOL_STATUS_FAULTED_DEV_R);
- if (find_vdev_problem(nvroot, vdev_missing, B_TRUE))
+ if (find_vdev_problem(nvroot, vdev_missing, NULL, B_TRUE))
return (ZPOOL_STATUS_MISSING_DEV_R);
- if (find_vdev_problem(nvroot, vdev_broken, B_TRUE))
+ if (find_vdev_problem(nvroot, vdev_broken, NULL, B_TRUE))
return (ZPOOL_STATUS_CORRUPT_LABEL_R);
/*
* Devices with errors
*/
- if (!isimport && find_vdev_problem(nvroot, vdev_errors, B_TRUE))
+ if (!isimport && find_vdev_problem(nvroot, vdev_errors, NULL, B_TRUE))
return (ZPOOL_STATUS_FAILING_DEV);
/*
* Offlined devices
*/
- if (find_vdev_problem(nvroot, vdev_offlined, B_TRUE))
+ if (find_vdev_problem(nvroot, vdev_offlined, NULL, B_TRUE))
return (ZPOOL_STATUS_OFFLINE_DEV);
/*
* Removed device
*/
- if (find_vdev_problem(nvroot, vdev_removed, B_TRUE))
+ if (find_vdev_problem(nvroot, vdev_removed, NULL, B_TRUE))
return (ZPOOL_STATUS_REMOVED_DEV);
/*
* Suboptimal, but usable, ashift configuration.
*/
- if (find_vdev_problem(nvroot, vdev_non_native_ashift, B_FALSE))
+ if (!isimport &&
+ getenv("ZPOOL_STATUS_NON_NATIVE_ASHIFT_IGNORE") == NULL &&
+ find_vdev_problem(nvroot, vdev_non_native_ashift, &ashift, B_FALSE))
return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
/*
@@ -510,8 +516,10 @@ zpool_get_status(zpool_handle_t *zhp, const char **msgid,
ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
compatibility[0] = '\0';
+ uint64_t ashift = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, NULL);
+
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata,
- compatibility);
+ compatibility, ashift);
if (msgid != NULL) {
if (ret >= NMSGID)
@@ -526,7 +534,7 @@ zpool_status_t
zpool_import_status(nvlist_t *config, const char **msgid,
zpool_errata_t *errata)
{
- zpool_status_t ret = check_status(config, B_TRUE, errata, NULL);
+ zpool_status_t ret = check_status(config, B_TRUE, errata, NULL, 0);
if (ret >= NMSGID)
*msgid = NULL;
diff --git a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi
index 7464b3adb254..263cad045f7a 100644
--- a/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi
+++ b/sys/contrib/openzfs/lib/libzfs_core/libzfs_core.abi
@@ -617,6 +617,7 @@
<array-type-def dimensions='1' type-id='de572c22' size-in-bits='1472' id='6d3c2f42'>
<subrange length='23' type-id='7359adad' id='fdd0f594'/>
</array-type-def>
+ <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/>
<array-type-def dimensions='1' type-id='3a47d82b' size-in-bits='256' id='a133ec23'>
<subrange length='4' type-id='7359adad' id='16fe7105'/>
</array-type-def>
@@ -988,13 +989,6 @@
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libspl/os/linux/getmntany.c' language='LANG_C99'>
- <array-type-def dimensions='1' type-id='d315442e' size-in-bits='16' id='811205dc'>
- <subrange length='1' type-id='7359adad' id='52f813b4'/>
- </array-type-def>
- <array-type-def dimensions='1' type-id='d3130597' size-in-bits='768' id='f63f23b9'>
- <subrange length='12' type-id='7359adad' id='84827bdc'/>
- </array-type-def>
- <type-decl name='long long int' size-in-bits='64' id='1eb56b1e'/>
<class-decl name='mnttab' size-in-bits='256' is-struct='yes' visibility='default' id='1b055409'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='mnt_special' type-id='26a90f95' visibility='default'/>
@@ -1029,93 +1023,6 @@
<var-decl name='mnt_minor' type-id='3502e3ff' visibility='default'/>
</data-member>
</class-decl>
- <typedef-decl name='__u16' type-id='8efea9e5' id='d315442e'/>
- <typedef-decl name='__s32' type-id='95e97e5e' id='3158a266'/>
- <typedef-decl name='__u32' type-id='f0981eeb' id='3f1a6b60'/>
- <typedef-decl name='__s64' type-id='1eb56b1e' id='49659421'/>
- <typedef-decl name='__u64' type-id='3a47d82b' id='d3130597'/>
- <class-decl name='statx_timestamp' size-in-bits='128' is-struct='yes' visibility='default' id='94101016'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='tv_sec' type-id='49659421' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='tv_nsec' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='96'>
- <var-decl name='__reserved' type-id='3158a266' visibility='default'/>
- </data-member>
- </class-decl>
- <class-decl name='statx' size-in-bits='2048' is-struct='yes' visibility='default' id='720b04c5'>
- <data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='stx_mask' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='32'>
- <var-decl name='stx_blksize' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='stx_attributes' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='stx_nlink' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='160'>
- <var-decl name='stx_uid' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='192'>
- <var-decl name='stx_gid' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='224'>
- <var-decl name='stx_mode' type-id='d315442e' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='240'>
- <var-decl name='__spare0' type-id='811205dc' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='256'>
- <var-decl name='stx_ino' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='320'>
- <var-decl name='stx_size' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='384'>
- <var-decl name='stx_blocks' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='448'>
- <var-decl name='stx_attributes_mask' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='512'>
- <var-decl name='stx_atime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='640'>
- <var-decl name='stx_btime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='768'>
- <var-decl name='stx_ctime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='896'>
- <var-decl name='stx_mtime' type-id='94101016' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1024'>
- <var-decl name='stx_rdev_major' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1056'>
- <var-decl name='stx_rdev_minor' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1088'>
- <var-decl name='stx_dev_major' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1120'>
- <var-decl name='stx_dev_minor' type-id='3f1a6b60' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1152'>
- <var-decl name='stx_mnt_id' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1216'>
- <var-decl name='__spare2' type-id='d3130597' visibility='default'/>
- </data-member>
- <data-member access='public' layout-offset-in-bits='1280'>
- <var-decl name='__spare3' type-id='f63f23b9' visibility='default'/>
- </data-member>
- </class-decl>
<class-decl name='mntent' size-in-bits='320' is-struct='yes' visibility='default' id='56fe4a37'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='mnt_fsname' type-id='26a90f95' visibility='default'/>
@@ -1191,8 +1098,6 @@
<pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/>
<pointer-type-def type-id='0bbec9cd' size-in-bits='64' id='62f7a03d'/>
<qualified-type-def type-id='62f7a03d' restrict='yes' id='f1cadedf'/>
- <pointer-type-def type-id='720b04c5' size-in-bits='64' id='936b8e35'/>
- <qualified-type-def type-id='936b8e35' restrict='yes' id='31d265b7'/>
<function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='e75a27e9'/>
<parameter type-id='3cad23cd'/>
@@ -1208,14 +1113,6 @@
<parameter type-id='95e97e5e'/>
<return type-id='26a90f95'/>
</function-decl>
- <function-decl name='statx' visibility='default' binding='global' size-in-bits='64'>
- <parameter type-id='95e97e5e'/>
- <parameter type-id='9d26089a'/>
- <parameter type-id='95e97e5e'/>
- <parameter type-id='f0981eeb'/>
- <parameter type-id='31d265b7'/>
- <return type-id='95e97e5e'/>
- </function-decl>
<function-decl name='stat64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='9d26089a'/>
<parameter type-id='f1cadedf'/>
diff --git a/sys/contrib/openzfs/lib/libzpool/kernel.c b/sys/contrib/openzfs/lib/libzpool/kernel.c
index 8ed374627264..70eba5099119 100644
--- a/sys/contrib/openzfs/lib/libzpool/kernel.c
+++ b/sys/contrib/openzfs/lib/libzpool/kernel.c
@@ -23,6 +23,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ * Copyright (c) 2025, Klara, Inc.
*/
#include <assert.h>
@@ -645,39 +646,60 @@ __dprintf(boolean_t dprint, const char *file, const char *func,
* cmn_err() and panic()
* =========================================================================
*/
-static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" };
-static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" };
-__attribute__((noreturn)) void
-vpanic(const char *fmt, va_list adx)
+static __attribute__((noreturn)) void
+panic_stop_or_abort(void)
{
- (void) fprintf(stderr, "error: ");
- (void) vfprintf(stderr, fmt, adx);
- (void) fprintf(stderr, "\n");
+ const char *stopenv = getenv("LIBZPOOL_PANIC_STOP");
+ if (stopenv != NULL && atoi(stopenv)) {
+ fputs("libzpool: LIBZPOOL_PANIC_STOP is set, sending "
+ "SIGSTOP to process group\n", stderr);
+ fflush(stderr);
+
+ kill(0, SIGSTOP);
+
+ fputs("libzpool: continued after panic stop, "
+ "aborting\n", stderr);
+ }
abort(); /* think of it as a "user-level crash dump" */
}
-__attribute__((noreturn)) void
-panic(const char *fmt, ...)
+static void
+vcmn_msg(int ce, const char *fmt, va_list adx)
{
- va_list adx;
+ switch (ce) {
+ case CE_IGNORE:
+ return;
+ case CE_CONT:
+ break;
+ case CE_NOTE:
+ fputs("libzpool: NOTICE: ", stderr);
+ break;
+ case CE_WARN:
+ fputs("libzpool: WARNING: ", stderr);
+ break;
+ case CE_PANIC:
+ fputs("libzpool: PANIC: ", stderr);
+ break;
+ default:
+ fputs("libzpool: [unknown severity %d]: ", stderr);
+ break;
+ }
- va_start(adx, fmt);
- vpanic(fmt, adx);
- va_end(adx);
+ vfprintf(stderr, fmt, adx);
+ if (ce != CE_CONT)
+ fputc('\n', stderr);
+ fflush(stderr);
}
void
vcmn_err(int ce, const char *fmt, va_list adx)
{
+ vcmn_msg(ce, fmt, adx);
+
if (ce == CE_PANIC)
- vpanic(fmt, adx);
- if (ce != CE_NOTE) { /* suppress noise in userland stress testing */
- (void) fprintf(stderr, "%s", ce_prefix[ce]);
- (void) vfprintf(stderr, fmt, adx);
- (void) fprintf(stderr, "%s", ce_suffix[ce]);
- }
+ panic_stop_or_abort();
}
void
@@ -690,6 +712,25 @@ cmn_err(int ce, const char *fmt, ...)
va_end(adx);
}
+__attribute__((noreturn)) void
+panic(const char *fmt, ...)
+{
+ va_list adx;
+
+ va_start(adx, fmt);
+ vcmn_msg(CE_PANIC, fmt, adx);
+ va_end(adx);
+
+ panic_stop_or_abort();
+}
+
+__attribute__((noreturn)) void
+vpanic(const char *fmt, va_list adx)
+{
+ vcmn_msg(CE_PANIC, fmt, adx);
+ panic_stop_or_abort();
+}
+
/*
* =========================================================================
* misc routines
diff --git a/sys/contrib/openzfs/man/man8/zdb.8 b/sys/contrib/openzfs/man/man8/zdb.8
index c3290ea14769..f51e24fa849c 100644
--- a/sys/contrib/openzfs/man/man8/zdb.8
+++ b/sys/contrib/openzfs/man/man8/zdb.8
@@ -144,6 +144,20 @@ subcommand.
Display statistics regarding the number, size
.Pq logical, physical and allocated
and deduplication of blocks.
+.It Fl -bin Ns = Ns ( Li lsize Ns | Ns Li psize Ns | Ns Li asize )
+When used with
+.Fl bb ,
+sort blocks into all three bins according to the given size (instead of binning
+a block for each size separately).
+.Pp
+For instance, with
+.Fl -bin Ns = Ns Li lsize ,
+a block with lsize of 16K and psize of 4K will be added to the 16K bin
+in all three columns.
+.It Fl -class Ns = Ns ( Li normal Ns | Ns Li special Ns | Ns Li dedup Ns | Ns Li other ) Ns Op , Ns …
+When used with
+.Fl bb ,
+only consider blocks from these allocation classes.
.It Fl B , -backup
Generate a backup stream, similar to
.Nm zfs Cm send ,
diff --git a/sys/contrib/openzfs/man/man8/zinject.8 b/sys/contrib/openzfs/man/man8/zinject.8
index 1d9e43aed5ec..704f6a7accd8 100644
--- a/sys/contrib/openzfs/man/man8/zinject.8
+++ b/sys/contrib/openzfs/man/man8/zinject.8
@@ -138,6 +138,20 @@ This injector is automatically cleared after the import is finished.
.
.It Xo
.Nm zinject
+.Fl E Ar delay
+.Op Fl a
+.Op Fl m
+.Op Fl f Ar freq
+.Op Fl l Ar level
+.Op Fl r Ar range
+.Op Fl T Ar iotype
+.Op Fl t Ar type Ns | Ns Fl b Ar bookmark
+.Xc
+Inject pipeline ready stage delays for the given object or bookmark.
+The delay is specified in milliseconds.
+.
+.It Xo
+.Nm zinject
.Fl I
.Op Fl s Ar seconds Ns | Ns Fl g Ar txgs
.Ar pool
diff --git a/sys/contrib/openzfs/man/man8/zpool-remove.8 b/sys/contrib/openzfs/man/man8/zpool-remove.8
index 4d5fc431d332..483d885f10fd 100644
--- a/sys/contrib/openzfs/man/man8/zpool-remove.8
+++ b/sys/contrib/openzfs/man/man8/zpool-remove.8
@@ -58,8 +58,8 @@ This command supports removing hot spare, cache, log, and both mirrored and
non-redundant primary top-level vdevs, including dedup and special vdevs.
.Pp
Top-level vdevs can only be removed if the primary pool storage does not contain
-a top-level raidz vdev, all top-level vdevs have the same sector size, and the
-keys for all encrypted datasets are loaded.
+a top-level raidz or draid vdev, all top-level vdevs have the same ashift size,
+and the keys for all encrypted datasets are loaded.
.Pp
Removing a top-level vdev reduces the total amount of space in the storage pool.
The specified device will be evacuated by copying all allocated space from it to
diff --git a/sys/contrib/openzfs/module/icp/algs/sha2/sha2_generic.c b/sys/contrib/openzfs/module/icp/algs/sha2/sha2_generic.c
index d0fcca798fa9..ad707341eec7 100644
--- a/sys/contrib/openzfs/module/icp/algs/sha2/sha2_generic.c
+++ b/sys/contrib/openzfs/module/icp/algs/sha2/sha2_generic.c
@@ -77,7 +77,8 @@ static const uint32_t SHA256_K[64] = {
h = g, g = f, f = e, e = d + T1; \
d = c, c = b, b = a, a = T1 + T2;
-static void sha256_generic(uint32_t state[8], const void *data, size_t num_blks)
+static void
+icp_sha256_generic(uint32_t state[8], const void *data, size_t num_blks)
{
uint64_t blk;
@@ -173,7 +174,8 @@ static const uint64_t SHA512_K[80] = {
0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
-static void sha512_generic(uint64_t state[8], const void *data, size_t num_blks)
+static void
+icp_sha512_generic(uint64_t state[8], const void *data, size_t num_blks)
{
uint64_t blk;
@@ -226,7 +228,8 @@ static void sha512_generic(uint64_t state[8], const void *data, size_t num_blks)
}
}
-static void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
+static void
+icp_sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
{
uint64_t pos = ctx->count[0];
uint64_t total = ctx->count[1];
@@ -258,7 +261,8 @@ static void sha256_update(sha256_ctx *ctx, const uint8_t *data, size_t len)
ctx->count[1] = total;
}
-static void sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len)
+static void
+icp_sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len)
{
uint64_t pos = ctx->count[0];
uint64_t total = ctx->count[1];
@@ -290,7 +294,8 @@ static void sha512_update(sha512_ctx *ctx, const uint8_t *data, size_t len)
ctx->count[1] = total;
}
-static void sha256_final(sha256_ctx *ctx, uint8_t *result, int bits)
+static void
+icp_sha256_final(sha256_ctx *ctx, uint8_t *result, int bits)
{
uint64_t mlen, pos = ctx->count[0];
uint8_t *m = ctx->wbuf;
@@ -334,7 +339,8 @@ static void sha256_final(sha256_ctx *ctx, uint8_t *result, int bits)
memset(ctx, 0, sizeof (*ctx));
}
-static void sha512_final(sha512_ctx *ctx, uint8_t *result, int bits)
+static void
+icp_sha512_final(sha512_ctx *ctx, uint8_t *result, int bits)
{
uint64_t mlen, pos = ctx->count[0];
uint8_t *m = ctx->wbuf, *r;
@@ -461,14 +467,14 @@ SHA2Update(SHA2_CTX *ctx, const void *data, size_t len)
switch (ctx->algotype) {
case SHA256:
- sha256_update(&ctx->sha256, data, len);
+ icp_sha256_update(&ctx->sha256, data, len);
break;
case SHA512:
case SHA512_HMAC_MECH_INFO_TYPE:
- sha512_update(&ctx->sha512, data, len);
+ icp_sha512_update(&ctx->sha512, data, len);
break;
case SHA512_256:
- sha512_update(&ctx->sha512, data, len);
+ icp_sha512_update(&ctx->sha512, data, len);
break;
}
}
@@ -479,32 +485,33 @@ SHA2Final(void *digest, SHA2_CTX *ctx)
{
switch (ctx->algotype) {
case SHA256:
- sha256_final(&ctx->sha256, digest, 256);
+ icp_sha256_final(&ctx->sha256, digest, 256);
break;
case SHA512:
case SHA512_HMAC_MECH_INFO_TYPE:
- sha512_final(&ctx->sha512, digest, 512);
+ icp_sha512_final(&ctx->sha512, digest, 512);
break;
case SHA512_256:
- sha512_final(&ctx->sha512, digest, 256);
+ icp_sha512_final(&ctx->sha512, digest, 256);
break;
}
}
/* the generic implementation is always okay */
-static boolean_t sha2_is_supported(void)
+static boolean_t
+icp_sha2_is_supported(void)
{
return (B_TRUE);
}
const sha256_ops_t sha256_generic_impl = {
.name = "generic",
- .transform = sha256_generic,
- .is_supported = sha2_is_supported
+ .transform = icp_sha256_generic,
+ .is_supported = icp_sha2_is_supported
};
const sha512_ops_t sha512_generic_impl = {
.name = "generic",
- .transform = sha512_generic,
- .is_supported = sha2_is_supported
+ .transform = icp_sha512_generic,
+ .is_supported = icp_sha2_is_supported
};
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c
index 4de48e013ec4..d0a9c662e6f0 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c
@@ -762,8 +762,7 @@ zfsctl_common_pathconf(struct vop_pathconf_args *ap)
return (0);
case _PC_MIN_HOLE_SIZE:
- *ap->a_retval = (int)SPA_MINBLOCKSIZE;
- return (0);
+ return (EINVAL);
case _PC_ACL_EXTENDED:
*ap->a_retval = 0;
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
index 411225786089..f34a2fd37a77 100644
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
@@ -4116,6 +4116,7 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
{
znode_t *zp;
zfsvfs_t *zfsvfs;
+ uint_t blksize, iosize;
int error;
switch (cmd) {
@@ -4127,8 +4128,20 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
*valp = 64;
return (0);
case _PC_MIN_HOLE_SIZE:
- *valp = (int)SPA_MINBLOCKSIZE;
- return (0);
+ iosize = vp->v_mount->mnt_stat.f_iosize;
+ if (vp->v_type == VREG) {
+ zp = VTOZ(vp);
+ blksize = zp->z_blksz;
+ if (zp->z_size <= blksize)
+ blksize = MAX(blksize, iosize);
+ *valp = (int)blksize;
+ return (0);
+ }
+ if (vp->v_type == VDIR) {
+ *valp = (int)iosize;
+ return (0);
+ }
+ return (EINVAL);
case _PC_ACL_EXTENDED:
#if 0 /* POSIX ACLs are not implemented for ZFS on FreeBSD yet. */
zp = VTOZ(vp);
@@ -4210,8 +4223,20 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
zfs_vmobject_wlock(object);
(void) vm_page_grab_pages(object, OFF_TO_IDX(start),
- VM_ALLOC_NORMAL | VM_ALLOC_WAITOK | VM_ALLOC_ZERO,
+ VM_ALLOC_NORMAL | VM_ALLOC_WAITOK,
ma, count);
+ if (!vm_page_all_valid(ma[count - 1])) {
+ /*
+ * Later in this function, we copy DMU data to
+ * invalid pages only. The last page may not be
+ * entirely filled though, if the file does not
+ * end on a page boundary. Therefore, we zero
+ * that last page here to make sure it does not
+ * contain garbage after the end of file.
+ */
+ ASSERT(vm_page_none_valid(ma[count - 1]));
+ vm_page_zero_invalid(ma[count - 1], FALSE);
+ }
zfs_vmobject_wunlock(object);
}
if (blksz == zp->z_blksz)
diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-zone.c b/sys/contrib/openzfs/module/os/linux/spl/spl-zone.c
index 45c2999a4bb1..b2eae5d00b10 100644
--- a/sys/contrib/openzfs/module/os/linux/spl/spl-zone.c
+++ b/sys/contrib/openzfs/module/os/linux/spl/spl-zone.c
@@ -25,6 +25,10 @@
* SUCH DAMAGE.
*/
+/*
+ * Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
+ */
+
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/kmem.h>
@@ -56,6 +60,19 @@ typedef struct zone_dataset {
} zone_dataset_t;
#ifdef CONFIG_USER_NS
+
+/*
+ * Linux 6.18 moved the generic namespace type away from ns->ops->type onto
+ * ns_common itself.
+ */
+#ifdef HAVE_NS_COMMON_TYPE
+#define ns_is_newuser(ns) \
+ ((ns)->ns_type == CLONE_NEWUSER)
+#else
+#define ns_is_newuser(ns) \
+ ((ns)->ops != NULL && (ns)->ops->type == CLONE_NEWUSER)
+#endif
+
/*
* Returns:
* - 0 on success
@@ -84,7 +101,7 @@ user_ns_get(int fd, struct user_namespace **userns)
goto done;
}
ns = get_proc_ns(file_inode(nsfile));
- if (ns->ops->type != CLONE_NEWUSER) {
+ if (!ns_is_newuser(ns)) {
error = ENOTTY;
goto done;
}
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/abd_os.c b/sys/contrib/openzfs/module/os/linux/zfs/abd_os.c
index 8a8316f63c48..18f2426fbbfc 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/abd_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/abd_os.c
@@ -23,6 +23,7 @@
* Copyright (c) 2014 by Chunwei Chen. All rights reserved.
* Copyright (c) 2019 by Delphix. All rights reserved.
* Copyright (c) 2023, 2024, Klara Inc.
+ * Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
*/
/*
@@ -1109,6 +1110,14 @@ abd_return_buf_copy(abd_t *abd, void *buf, size_t n)
#define ABD_ITER_PAGE_SIZE(page) (PAGESIZE)
#endif
+#ifndef nth_page
+/*
+ * Since 6.18 nth_page() no longer exists, and is no longer required to iterate
+ * within a single SG entry, so we replace it with a simple addition.
+ */
+#define nth_page(p, n) ((p)+(n))
+#endif
+
void
abd_iter_page(struct abd_iter *aiter)
{
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c
index daa4b5776837..934d74a112fd 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c
@@ -2524,7 +2524,7 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
* Also note: DOS R/O is ignored for directories.
*/
if ((v4_mode & WRITE_MASK_DATA) &&
- S_ISDIR(ZTOI(zp)->i_mode) &&
+ !S_ISDIR(ZTOI(zp)->i_mode) &&
(zp->z_pflags & ZFS_READONLY)) {
return (SET_ERROR(EPERM));
}
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c
index 6106726651a3..e845ad69ad78 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c
@@ -2033,10 +2033,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns)
goto out3;
}
- if ((mask & ATTR_SIZE) && (zp->z_pflags & ZFS_READONLY)) {
- err = SET_ERROR(EPERM);
- goto out3;
- }
+ /* ZFS_READONLY will be handled in zfs_zaccess() */
/*
* Verify timestamps doesn't overflow 32 bits.
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
index d07317b0d910..02965ac8cbee 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
@@ -23,6 +23,7 @@
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
* Copyright (c) 2015 by Chunwei Chen. All rights reserved.
* Copyright (c) 2025, Klara, Inc.
+ * Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
*/
@@ -478,6 +479,7 @@ zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
return (ret);
}
+#ifdef HAVE_WRITE_CACHE_PAGES
#ifdef HAVE_WRITEPAGE_T_FOLIO
static int
zpl_putfolio(struct folio *pp, struct writeback_control *wbc, void *data)
@@ -499,6 +501,78 @@ zpl_write_cache_pages(struct address_space *mapping,
#endif
return (result);
}
+#else
+static inline int
+zpl_write_cache_pages(struct address_space *mapping,
+ struct writeback_control *wbc, void *data)
+{
+ pgoff_t start = wbc->range_start >> PAGE_SHIFT;
+ pgoff_t end = wbc->range_end >> PAGE_SHIFT;
+
+ struct folio_batch fbatch;
+ folio_batch_init(&fbatch);
+
+ /*
+ * This atomically (-ish) tags all DIRTY pages in the range with
+ * TOWRITE, allowing users to continue dirtying or undirtying pages
+ * while we get on with writeback, without us treading on each other.
+ */
+ tag_pages_for_writeback(mapping, start, end);
+
+ int err = 0;
+ unsigned int npages;
+
+ /*
+ * Grab references to the TOWRITE pages just flagged. This may not get
+ * all of them, so we do it in a loop until there are none left.
+ */
+ while ((npages = filemap_get_folios_tag(mapping, &start, end,
+ PAGECACHE_TAG_TOWRITE, &fbatch)) != 0) {
+
+ /* Loop over each page and write it out. */
+ struct folio *folio;
+ while ((folio = folio_batch_next(&fbatch)) != NULL) {
+ folio_lock(folio);
+
+ /*
+ * If the folio has been remapped, or is no longer
+ * dirty, then there's nothing to do.
+ */
+ if (folio->mapping != mapping ||
+ !folio_test_dirty(folio)) {
+ folio_unlock(folio);
+ continue;
+ }
+
+ /*
+ * If writeback is already in progress, wait for it to
+ * finish. We continue after this even if the page
+ * ends up clean; zfs_putpage() will skip it if no
+ * further work is required.
+ */
+ while (folio_test_writeback(folio))
+ folio_wait_bit(folio, PG_writeback);
+
+ /*
+ * Write it out and collect any error. zfs_putpage()
+ * will clear the TOWRITE and DIRTY flags, and return
+ * with the page unlocked.
+ */
+ int ferr = zpl_putpage(&folio->page, wbc, data);
+ if (err == 0 && ferr != 0)
+ err = ferr;
+
+ /* Housekeeping for the caller. */
+ wbc->nr_to_write -= folio_nr_pages(folio);
+ }
+
+ /* Release any remaining references on the batch. */
+ folio_batch_release(&fbatch);
+ }
+
+ return (err);
+}
+#endif
static int
zpl_writepages(struct address_space *mapping, struct writeback_control *wbc)
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c b/sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c
index 444948d03cb3..347b352506e5 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c
@@ -23,6 +23,7 @@
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
* Copyright (c) 2023, Datto Inc. All rights reserved.
* Copyright (c) 2025, Klara, Inc.
+ * Copyright (c) 2025, Rob Norris <robn@despairlabs.com>
*/
@@ -33,6 +34,7 @@
#include <sys/zpl.h>
#include <linux/iversion.h>
#include <linux/version.h>
+#include <linux/vfs_compat.h>
/*
* What to do when the last reference to an inode is released. If 0, the kernel
@@ -104,7 +106,7 @@ zpl_dirty_inode(struct inode *ip, int flags)
* reporting memory pressure and requests OpenZFS release some memory (see
* zfs_prune()).
*
- * When set to 1, we call generic_delete_node(), which always returns "destroy
+ * When set to 1, we call generic_delete_inode(), which always returns "destroy
* immediately", resulting in inodes being destroyed immediately, releasing
* their associated dnodes and dbufs to the dbuf cached and the ARC to be
* evicted as normal.
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
index 967a018640e1..fe939150b641 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c
@@ -21,7 +21,7 @@
*/
/*
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
- * Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
+ * Copyright (c) 2024, 2025, Rob Norris <robn@despairlabs.com>
* Copyright (c) 2024, 2025, Klara, Inc.
*/
@@ -337,16 +337,14 @@ zvol_discard(zv_request_t *zvr)
}
/*
- * Align the request to volume block boundaries when a secure erase is
- * not required. This will prevent dnode_free_range() from zeroing out
- * the unaligned parts which is slow (read-modify-write) and useless
- * since we are not freeing any space by doing so.
+ * Align the request to volume block boundaries. This will prevent
+ * dnode_free_range() from zeroing out the unaligned parts which is
+ * slow (read-modify-write) and useless since we are not freeing any
+ * space by doing so.
*/
- if (!io_is_secure_erase(bio, rq)) {
- start = P2ROUNDUP(start, zv->zv_volblocksize);
- end = P2ALIGN_TYPED(end, zv->zv_volblocksize, uint64_t);
- size = end - start;
- }
+ start = P2ROUNDUP(start, zv->zv_volblocksize);
+ end = P2ALIGN_TYPED(end, zv->zv_volblocksize, uint64_t);
+ size = end - start;
if (start >= end)
goto unlock;
@@ -467,6 +465,24 @@ zvol_read_task(void *arg)
zv_request_task_free(task);
}
+/*
+ * Note:
+ *
+ * The kernel uses different enum names for the IO opcode, depending on the
+ * kernel version ('req_opf', 'req_op'). To sidestep this, use macros rather
+ * than inline functions for these checks.
+ */
+/* Should this IO go down the zvol write path? */
+#define ZVOL_OP_IS_WRITE(op) \
+ (op == REQ_OP_WRITE || \
+ op == REQ_OP_FLUSH || \
+ op == REQ_OP_DISCARD)
+
+/* Is this IO type supported by zvols? */
+#define ZVOL_OP_IS_SUPPORTED(op) (op == REQ_OP_READ || ZVOL_OP_IS_WRITE(op))
+
+/* Get the IO opcode */
+#define ZVOL_OP(bio, rq) (bio != NULL ? bio_op(bio) : req_op(rq))
/*
* Process a BIO or request
@@ -486,27 +502,32 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
uint64_t size = io_size(bio, rq);
int rw;
- if (rq != NULL) {
- /*
- * Flush & trim requests go down the zvol_write codepath. Or
- * more specifically:
- *
- * If request is a write, or if it's op_is_sync() and not a
- * read, or if it's a flush, or if it's a discard, then send the
- * request down the write path.
- */
- if (op_is_write(rq->cmd_flags) ||
- (op_is_sync(rq->cmd_flags) && req_op(rq) != REQ_OP_READ) ||
- req_op(rq) == REQ_OP_FLUSH ||
- op_is_discard(rq->cmd_flags)) {
- rw = WRITE;
- } else {
- rw = READ;
- }
+ if (unlikely(!ZVOL_OP_IS_SUPPORTED(ZVOL_OP(bio, rq)))) {
+ zfs_dbgmsg("Unsupported zvol %s, op=%d, flags=0x%x",
+ rq != NULL ? "request" : "BIO",
+ ZVOL_OP(bio, rq),
+ rq != NULL ? rq->cmd_flags : bio->bi_opf);
+ ASSERT(ZVOL_OP_IS_SUPPORTED(ZVOL_OP(bio, rq)));
+ zvol_end_io(bio, rq, SET_ERROR(ENOTSUPP));
+ goto out;
+ }
+
+ if (ZVOL_OP_IS_WRITE(ZVOL_OP(bio, rq))) {
+ rw = WRITE;
} else {
- rw = bio_data_dir(bio);
+ rw = READ;
}
+ /*
+ * Sanity check
+ *
+ * If we're a BIO, check our rw matches the kernel's
+ * bio_data_dir(bio) rw. We need to check because we support fewer
+ * IO operations, and want to verify that what we think are reads and
+ * writes from those operations match what the kernel thinks.
+ */
+ ASSERT(rq != NULL || rw == bio_data_dir(bio));
+
if (unlikely(zv->zv_flags & ZVOL_REMOVING)) {
zvol_end_io(bio, rq, SET_ERROR(ENXIO));
goto out;
@@ -610,7 +631,7 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
* interfaces lack this functionality (they block waiting for
* the i/o to complete).
*/
- if (io_is_discard(bio, rq) || io_is_secure_erase(bio, rq)) {
+ if (io_is_discard(bio, rq)) {
if (force_sync) {
zvol_discard(&zvr);
} else {
@@ -1011,12 +1032,12 @@ zvol_os_update_volsize(zvol_state_t *zv, uint64_t volsize)
* tiny devices. For devices over 1 Mib a standard head and sector count
* is used to keep the cylinders count reasonable.
*/
-static int
-zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+static inline int
+zvol_getgeo_impl(struct gendisk *disk, struct hd_geometry *geo)
{
+ zvol_state_t *zv = atomic_load_ptr(&disk->private_data);
sector_t sectors;
- zvol_state_t *zv = atomic_load_ptr(&bdev->bd_disk->private_data);
ASSERT3P(zv, !=, NULL);
ASSERT3U(zv->zv_open_count, >, 0);
@@ -1036,6 +1057,20 @@ zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return (0);
}
+#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_GETGEO_GENDISK
+static int
+zvol_getgeo(struct gendisk *disk, struct hd_geometry *geo)
+{
+ return (zvol_getgeo_impl(disk, geo));
+}
+#else
+static int
+zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ return (zvol_getgeo_impl(bdev->bd_disk, geo));
+}
+#endif
+
/*
* Why have two separate block_device_operations structs?
*
@@ -1479,7 +1514,7 @@ zvol_os_remove_minor(zvol_state_t *zv)
if (zso->use_blk_mq)
blk_mq_free_tag_set(&zso->tag_set);
- ida_simple_remove(&zvol_ida, MINOR(zso->zvo_dev) >> ZVOL_MINOR_BITS);
+ ida_free(&zvol_ida, MINOR(zso->zvo_dev) >> ZVOL_MINOR_BITS);
kmem_free(zso, sizeof (struct zvol_state_os));
@@ -1634,7 +1669,7 @@ zvol_os_create_minor(const char *name)
if (zvol_inhibit_dev)
return (0);
- idx = ida_simple_get(&zvol_ida, 0, 0, kmem_flags_convert(KM_SLEEP));
+ idx = ida_alloc(&zvol_ida, kmem_flags_convert(KM_SLEEP));
if (idx < 0)
return (SET_ERROR(-idx));
minor = idx << ZVOL_MINOR_BITS;
@@ -1642,7 +1677,7 @@ zvol_os_create_minor(const char *name)
/* too many partitions can cause an overflow */
zfs_dbgmsg("zvol: create minor overflow: %s, minor %u/%u",
name, minor, MINOR(minor));
- ida_simple_remove(&zvol_ida, idx);
+ ida_free(&zvol_ida, idx);
return (SET_ERROR(EINVAL));
}
@@ -1650,7 +1685,7 @@ zvol_os_create_minor(const char *name)
if (zv) {
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
mutex_exit(&zv->zv_state_lock);
- ida_simple_remove(&zvol_ida, idx);
+ ida_free(&zvol_ida, idx);
return (SET_ERROR(EEXIST));
}
@@ -1750,7 +1785,7 @@ out_doi:
rw_exit(&zvol_state_lock);
error = zvol_os_add_disk(zv->zv_zso->zvo_disk);
} else {
- ida_simple_remove(&zvol_ida, idx);
+ ida_free(&zvol_ida, idx);
}
return (error);
diff --git a/sys/contrib/openzfs/module/zcommon/zfs_prop.c b/sys/contrib/openzfs/module/zcommon/zfs_prop.c
index 864e3898b365..9190ae0362ea 100644
--- a/sys/contrib/openzfs/module/zcommon/zfs_prop.c
+++ b/sys/contrib/openzfs/module/zcommon/zfs_prop.c
@@ -364,8 +364,8 @@ zfs_prop_init(void)
static const zprop_index_t xattr_table[] = {
{ "off", ZFS_XATTR_OFF },
- { "on", ZFS_XATTR_SA },
{ "sa", ZFS_XATTR_SA },
+ { "on", ZFS_XATTR_SA },
{ "dir", ZFS_XATTR_DIR },
{ NULL }
};
diff --git a/sys/contrib/openzfs/module/zfs/arc.c b/sys/contrib/openzfs/module/zfs/arc.c
index df41e3b49204..dbb5e942e2e6 100644
--- a/sys/contrib/openzfs/module/zfs/arc.c
+++ b/sys/contrib/openzfs/module/zfs/arc.c
@@ -1157,7 +1157,7 @@ buf_fini(void)
#if defined(_KERNEL)
/*
* Large allocations which do not require contiguous pages
- * should be using vmem_free() in the linux kernel\
+ * should be using vmem_free() in the linux kernel.
*/
vmem_free(buf_hash_table.ht_table,
(buf_hash_table.ht_mask + 1) * sizeof (void *));
@@ -1392,6 +1392,7 @@ arc_get_complevel(arc_buf_t *buf)
return (buf->b_hdr->b_complevel);
}
+__maybe_unused
static inline boolean_t
arc_buf_is_shared(arc_buf_t *buf)
{
@@ -4650,10 +4651,10 @@ arc_flush_task(void *arg)
arc_flush_impl(spa_guid, B_FALSE);
arc_async_flush_remove(spa_guid, af->af_cache_level);
- uint64_t elaspsed = NSEC2MSEC(gethrtime() - start_time);
- if (elaspsed > 0) {
+ uint64_t elapsed = NSEC2MSEC(gethrtime() - start_time);
+ if (elapsed > 0) {
zfs_dbgmsg("spa %llu arc flushed in %llu ms",
- (u_longlong_t)spa_guid, (u_longlong_t)elaspsed);
+ (u_longlong_t)spa_guid, (u_longlong_t)elapsed);
}
}
@@ -9151,7 +9152,7 @@ top:
if (dev->l2ad_first) {
/*
* This is the first sweep through the device. There is
- * nothing to evict. We have already trimmmed the
+ * nothing to evict. We have already trimmed the
* whole device.
*/
goto out;
@@ -10085,12 +10086,12 @@ l2arc_device_teardown(void *arg)
kmem_free(remdev->l2ad_dev_hdr, remdev->l2ad_dev_hdr_asize);
vmem_free(remdev, sizeof (l2arc_dev_t));
- uint64_t elaspsed = NSEC2MSEC(gethrtime() - start_time);
- if (elaspsed > 0) {
+ uint64_t elapsed = NSEC2MSEC(gethrtime() - start_time);
+ if (elapsed > 0) {
zfs_dbgmsg("spa %llu, vdev %llu removed in %llu ms",
(u_longlong_t)rva->rva_spa_gid,
(u_longlong_t)rva->rva_vdev_gid,
- (u_longlong_t)elaspsed);
+ (u_longlong_t)elapsed);
}
if (rva->rva_async)
diff --git a/sys/contrib/openzfs/module/zfs/mmp.c b/sys/contrib/openzfs/module/zfs/mmp.c
index 7db72b9b04b0..fd46127b6068 100644
--- a/sys/contrib/openzfs/module/zfs/mmp.c
+++ b/sys/contrib/openzfs/module/zfs/mmp.c
@@ -446,7 +446,7 @@ mmp_write_uberblock(spa_t *spa)
uint64_t offset;
hrtime_t lock_acquire_time = gethrtime();
- spa_config_enter_mmp(spa, SCL_STATE, mmp_tag, RW_READER);
+ spa_config_enter_priority(spa, SCL_STATE, mmp_tag, RW_READER);
lock_acquire_time = gethrtime() - lock_acquire_time;
if (lock_acquire_time > (MSEC2NSEC(MMP_MIN_INTERVAL) / 10))
zfs_dbgmsg("MMP SCL_STATE acquisition pool '%s' took %llu ns "
diff --git a/sys/contrib/openzfs/module/zfs/spa_misc.c b/sys/contrib/openzfs/module/zfs/spa_misc.c
index a539468df6a1..0bead6d49666 100644
--- a/sys/contrib/openzfs/module/zfs/spa_misc.c
+++ b/sys/contrib/openzfs/module/zfs/spa_misc.c
@@ -510,7 +510,7 @@ spa_config_tryenter(spa_t *spa, int locks, const void *tag, krw_t rw)
static void
spa_config_enter_impl(spa_t *spa, int locks, const void *tag, krw_t rw,
- int mmp_flag)
+ int priority_flag)
{
(void) tag;
int wlocks_held = 0;
@@ -526,7 +526,7 @@ spa_config_enter_impl(spa_t *spa, int locks, const void *tag, krw_t rw,
mutex_enter(&scl->scl_lock);
if (rw == RW_READER) {
while (scl->scl_writer ||
- (!mmp_flag && scl->scl_write_wanted)) {
+ (!priority_flag && scl->scl_write_wanted)) {
cv_wait(&scl->scl_cv, &scl->scl_lock);
}
} else {
@@ -551,7 +551,7 @@ spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw)
}
/*
- * The spa_config_enter_mmp() allows the mmp thread to cut in front of
+ * The spa_config_enter_priority() allows the mmp thread to cut in front of
* outstanding write lock requests. This is needed since the mmp updates are
* time sensitive and failure to service them promptly will result in a
* suspended pool. This pool suspension has been seen in practice when there is
@@ -560,7 +560,7 @@ spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw)
*/
void
-spa_config_enter_mmp(spa_t *spa, int locks, const void *tag, krw_t rw)
+spa_config_enter_priority(spa_t *spa, int locks, const void *tag, krw_t rw)
{
spa_config_enter_impl(spa, locks, tag, rw, 1);
}
diff --git a/sys/contrib/openzfs/module/zfs/vdev_removal.c b/sys/contrib/openzfs/module/zfs/vdev_removal.c
index 2f7a739da241..abb71543e3ab 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_removal.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_removal.c
@@ -51,34 +51,70 @@
#include <sys/trace_zfs.h>
/*
- * This file contains the necessary logic to remove vdevs from a
- * storage pool. Currently, the only devices that can be removed
- * are log, cache, and spare devices; and top level vdevs from a pool
- * w/o raidz or mirrors. (Note that members of a mirror can be removed
- * by the detach operation.)
+ * This file contains the necessary logic to remove vdevs from a storage
+ * pool. Note that members of a mirror can be removed by the detach
+ * operation. Currently, the only devices that can be removed are:
*
- * Log vdevs are removed by evacuating them and then turning the vdev
- * into a hole vdev while holding spa config locks.
+ * 1) Traditional hot spare and cache vdevs. Note that draid distributed
+ * spares are fixed at creation time and cannot be removed.
*
- * Top level vdevs are removed and converted into an indirect vdev via
- * a multi-step process:
+ * 2) Log vdevs are removed by evacuating them and then turning the vdev
+ * into a hole vdev while holding spa config locks.
*
- * - Disable allocations from this device (spa_vdev_remove_top).
+ * 3) Top-level singleton and mirror vdevs, including dedup and special
+ * vdevs, are removed and converted into an indirect vdev via a
+ * multi-step process:
*
- * - From a new thread (spa_vdev_remove_thread), copy data from
- * the removing vdev to a different vdev. The copy happens in open
- * context (spa_vdev_copy_impl) and issues a sync task
- * (vdev_mapping_sync) so the sync thread can update the partial
- * indirect mappings in core and on disk.
+ * - Disable allocations from this device (spa_vdev_remove_top).
*
- * - If a free happens during a removal, it is freed from the
- * removing vdev, and if it has already been copied, from the new
- * location as well (free_from_removing_vdev).
+ * - From a new thread (spa_vdev_remove_thread), copy data from the
+ * removing vdev to a different vdev. The copy happens in open context
+ * (spa_vdev_copy_impl) and issues a sync task (vdev_mapping_sync) so
+ * the sync thread can update the partial indirect mappings in core
+ * and on disk.
*
- * - After the removal is completed, the copy thread converts the vdev
- * into an indirect vdev (vdev_remove_complete) before instructing
- * the sync thread to destroy the space maps and finish the removal
- * (spa_finish_removal).
+ * - If a free happens during a removal, it is freed from the removing
+ * vdev, and if it has already been copied, from the new location as
+ * well (free_from_removing_vdev).
+ *
+ * - After the removal is completed, the copy thread converts the vdev
+ * into an indirect vdev (vdev_remove_complete) before instructing
+ * the sync thread to destroy the space maps and finish the removal
+ * (spa_finish_removal).
+ *
+ * The following constraints currently apply primary device removal:
+ *
+ * - All vdevs must be online, healthy, and not be missing any data
+ * according to the DTLs.
+ *
+ * - When removing a singleton or mirror vdev, regardless of it's a
+ * special, dedup, or primary device, it must have the same ashift
+ * as the devices in the normal allocation class. Furthermore, all
+ * vdevs in the normal allocation class must have the same ashift to
+ * ensure the new allocations never includes additional padding.
+ *
+ * - The normal allocation class cannot contain any raidz or draid
+ * top-level vdevs since segments are copied without regard for block
+ * boundaries. This makes it impossible to calculate the required
+ * parity columns when using these vdev types as the destination.
+ *
+ * - The encryption keys must be loaded so the ZIL logs can be reset
+ * in order to prevent writing to the device being removed.
+ *
+ * N.B. ashift and raidz/draid constraints for primary top-level device
+ * removal could be slightly relaxed if it were possible to request that
+ * DVAs from a mirror or singleton in the specified allocation class be
+ * used (metaslab_alloc_dva).
+ *
+ * This flexibility would be particularly useful for raidz/draid pools which
+ * often include a mirrored special device. If a mistakenly added top-level
+ * singleton were added it could then still be removed at the cost of some
+ * special device capacity. This may be a worthwhile tradeoff depending on
+ * the pool capacity and expense (cost, complexity, time) of creating a new
+ * pool and copying all of the data to correct the configuration.
+ *
+ * Furthermore, while not currently supported it should be possible to allow
+ * vdevs of any type to be removed as long as they've never been written to.
*/
typedef struct vdev_copy_arg {
diff --git a/sys/contrib/openzfs/module/zfs/zio.c b/sys/contrib/openzfs/module/zfs/zio.c
index 4cf8912d4269..aeea58bedfe4 100644
--- a/sys/contrib/openzfs/module/zfs/zio.c
+++ b/sys/contrib/openzfs/module/zfs/zio.c
@@ -4574,8 +4574,29 @@ zio_vdev_io_start(zio_t *zio)
ASSERT0(zio->io_child_error[ZIO_CHILD_VDEV]);
if (vd == NULL) {
- if (!(zio->io_flags & ZIO_FLAG_CONFIG_WRITER))
- spa_config_enter(spa, SCL_ZIO, zio, RW_READER);
+ if (!(zio->io_flags & ZIO_FLAG_CONFIG_WRITER)) {
+ /*
+ * A deadlock workaround. The ddt_prune_unique_entries()
+ * -> prune_candidates_sync() code path takes the
+ * SCL_ZIO reader lock and may request it again here.
+ * If there is another thread who wants the SCL_ZIO
+ * writer lock, then scl_write_wanted will be set.
+ * Thus, the spa_config_enter_priority() is used to
+ * ignore pending writer requests.
+ *
+ * The locking should be revised to remove the need
+ * for this workaround. If that's not workable then
+ * it should only be applied to the zios involved in
+ * the pruning process. This impacts the read/write
+ * I/O balance while pruning.
+ */
+ if (spa->spa_active_ddt_prune)
+ spa_config_enter_priority(spa, SCL_ZIO, zio,
+ RW_READER);
+ else
+ spa_config_enter(spa, SCL_ZIO, zio,
+ RW_READER);
+ }
/*
* The mirror_ops handle multiple DVAs in a single BP.
@@ -5305,6 +5326,16 @@ zio_ready(zio_t *zio)
return (NULL);
}
+ if (zio_injection_enabled) {
+ hrtime_t target = zio_handle_ready_delay(zio);
+ if (target != 0 && zio->io_target_timestamp == 0) {
+ zio->io_stage >>= 1;
+ zio->io_target_timestamp = target;
+ zio_delay_interrupt(zio);
+ return (NULL);
+ }
+ }
+
if (zio->io_ready) {
ASSERT(IO_IS_ALLOCATING(zio));
ASSERT(BP_GET_BIRTH(bp) == zio->io_txg ||
diff --git a/sys/contrib/openzfs/module/zfs/zio_inject.c b/sys/contrib/openzfs/module/zfs/zio_inject.c
index 981a1be4847c..287577018ed1 100644
--- a/sys/contrib/openzfs/module/zfs/zio_inject.c
+++ b/sys/contrib/openzfs/module/zfs/zio_inject.c
@@ -827,6 +827,44 @@ zio_handle_export_delay(spa_t *spa, hrtime_t elapsed)
zio_handle_pool_delay(spa, elapsed, ZINJECT_DELAY_EXPORT);
}
+/*
+ * For testing, inject a delay before ready state.
+ */
+hrtime_t
+zio_handle_ready_delay(zio_t *zio)
+{
+ inject_handler_t *handler;
+ hrtime_t now = gethrtime();
+ hrtime_t target = 0;
+
+ /*
+ * Ignore I/O not associated with any logical data.
+ */
+ if (zio->io_logical == NULL)
+ return (0);
+
+ rw_enter(&inject_lock, RW_READER);
+
+ for (handler = list_head(&inject_handlers); handler != NULL;
+ handler = list_next(&inject_handlers, handler)) {
+ if (zio->io_spa != handler->zi_spa ||
+ handler->zi_record.zi_cmd != ZINJECT_DELAY_READY)
+ continue;
+
+ /* If this handler matches, inject the delay */
+ if (zio_match_iotype(zio, handler->zi_record.zi_iotype) &&
+ zio_match_handler(&zio->io_logical->io_bookmark,
+ zio->io_bp ? BP_GET_TYPE(zio->io_bp) : DMU_OT_NONE,
+ zio_match_dva(zio), &handler->zi_record, zio->io_error)) {
+ target = now + (hrtime_t)handler->zi_record.zi_timer;
+ break;
+ }
+ }
+
+ rw_exit(&inject_lock);
+ return (target);
+}
+
static int
zio_calculate_range(const char *pool, zinject_record_t *record)
{
diff --git a/sys/contrib/openzfs/module/zfs/zvol.c b/sys/contrib/openzfs/module/zfs/zvol.c
index faced0db7e9e..00f98168d3d8 100644
--- a/sys/contrib/openzfs/module/zfs/zvol.c
+++ b/sys/contrib/openzfs/module/zfs/zvol.c
@@ -410,7 +410,7 @@ zvol_set_volthreading(const char *name, boolean_t value)
{
zvol_state_t *zv = zvol_find_by_name(name, RW_NONE);
if (zv == NULL)
- return (SET_ERROR(ENOENT));
+ return (-1);
zv->zv_threading = value;
mutex_exit(&zv->zv_state_lock);
return (0);
diff --git a/sys/contrib/openzfs/tests/runfiles/common.run b/sys/contrib/openzfs/tests/runfiles/common.run
index b0e8f8d43074..9f531411fbe1 100644
--- a/sys/contrib/openzfs/tests/runfiles/common.run
+++ b/sys/contrib/openzfs/tests/runfiles/common.run
@@ -1090,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/sanity.run b/sys/contrib/openzfs/tests/runfiles/sanity.run
index b56ffc3a4a2d..249b415029c4 100644
--- a/sys/contrib/openzfs/tests/runfiles/sanity.run
+++ b/sys/contrib/openzfs/tests/runfiles/sanity.run
@@ -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/zfs-tests/cmd/mmap_seek.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/mmap_seek.c
index 45ba17e36c35..f46980cad111 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/mmap_seek.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/mmap_seek.c
@@ -47,25 +47,34 @@
#endif
static void
+seek_expect(int fd, off_t offset, int whence, off_t expect_offset)
+{
+ errno = 0;
+ off_t seek_offset = lseek(fd, offset, whence);
+ if (seek_offset == expect_offset)
+ return;
+
+ int err = errno;
+ fprintf(stderr, "lseek(fd, %ld, SEEK_%s) = %ld (expected %ld)",
+ offset, (whence == SEEK_DATA ? "DATA" : "HOLE"),
+ seek_offset, expect_offset);
+ if (err != 0)
+ fprintf(stderr, " (errno %d [%s])\n", err, strerror(err));
+ else
+ fputc('\n', stderr);
+ exit(2);
+}
+
+static inline void
seek_data(int fd, off_t offset, off_t expected)
{
- off_t data_offset = lseek(fd, offset, SEEK_DATA);
- if (data_offset != expected) {
- fprintf(stderr, "lseek(fd, %d, SEEK_DATA) = %d (expected %d)\n",
- (int)offset, (int)data_offset, (int)expected);
- exit(2);
- }
+ seek_expect(fd, offset, SEEK_DATA, expected);
}
-static void
+static inline void
seek_hole(int fd, off_t offset, off_t expected)
{
- off_t hole_offset = lseek(fd, offset, SEEK_HOLE);
- if (hole_offset != expected) {
- fprintf(stderr, "lseek(fd, %d, SEEK_HOLE) = %d (expected %d)\n",
- (int)offset, (int)hole_offset, (int)expected);
- exit(2);
- }
+ seek_expect(fd, offset, SEEK_HOLE, expected);
}
int
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
index 43eaa45910ba..678c01b58f94 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
@@ -2234,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/zpool_reopen/zpool_reopen_004_pos.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh
index 2bd9f616170b..1a9774331ba1 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_reopen/zpool_reopen_004_pos.ksh
@@ -47,6 +47,8 @@ function cleanup
# bring back removed disk online for further tests
insert_disk $REMOVED_DISK $scsi_host
poolexists $TESTPOOL && destroy_pool $TESTPOOL
+ # Since the disk was offline during destroy, remove the label
+ zpool labelclear $DISK2 -f
}
log_assert "Testing zpool reopen with pool name as argument"
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/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_trim.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_trim.ksh
index bb697b76a9f3..9de308c4a11a 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_trim.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_trim.ksh
@@ -41,6 +41,7 @@
# 5. TRIM the first 1MB and last 2MB of the 5MB block of data.
# 6. Observe 2MB of used space on the zvol
# 7. Verify the trimmed regions are zero'd on the zvol
+# 8. Verify Secure Erase does not work on zvols (Linux only)
verify_runnable "global"
@@ -56,6 +57,7 @@ if is_linux ; then
else
trimcmd='blkdiscard'
fi
+ secure_trimcmd="$trimcmd --secure"
else
# By default, FreeBSD 'trim' always does a dry-run. '-f' makes
# it perform the actual operation.
@@ -114,6 +116,11 @@ function do_test {
log_must diff $datafile1 $datafile2
log_must rm $datafile1 $datafile2
+
+ # Secure erase should not work (Linux check only).
+ if [ -n "$secure_trimcmd" ] ; then
+ log_mustnot $secure_trimcmd $zvolpath
+ fi
}
log_assert "Verify that a ZFS volume can be TRIMed"