aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2026-05-06 21:46:01 +0000
committerMartin Matuska <mm@FreeBSD.org>2026-05-06 23:07:56 +0000
commitefa8679e7f69c9cc225613827d9f75644cca5b3b (patch)
tree762da69225b82f7d5eae6281ec75e3b8875d8d49
parentc4af3f13a4e9932968d92872aaf22312a6e79e4e (diff)
parenta12c6ed62fcd06093b95616515e4716b0b0bc038 (diff)
zfs: merge openzfs/zfs@a12c6ed62
Notable upstream pull request merges: #18473 b8d959640 Fix rare cksum errors after rebuild #18477 e78a51dd6 Fix off-by-one in PREVIOUSLY_REDACTED handler that drops last block #18482 d5099c330 Initialize vr_last_txg for rebuild #18483 872f01019 Zstd: rework ZSTD_isError symbol renaming #18489 366b1f9a3 Fix long POSIX_FADV_DONTNEED for single block files Obtained from: OpenZFS OpenZFS commit: a12c6ed62fcd06093b95616515e4716b0b0bc038
-rwxr-xr-xsys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh16
-rw-r--r--sys/contrib/openzfs/.github/workflows/zfs-qemu-packages.yml2
-rw-r--r--sys/contrib/openzfs/.github/workflows/zfs-qemu.yml10
-rw-r--r--sys/contrib/openzfs/cmd/zed/zed_event.c2
-rw-r--r--sys/contrib/openzfs/cmd/zfs/zfs_main.c3
-rw-r--r--sys/contrib/openzfs/config/kernel-dentry-alias.m432
-rw-r--r--sys/contrib/openzfs/config/kernel.m42
-rw-r--r--sys/contrib/openzfs/etc/systemd/system-generators/zfs-mount-generator.c5
-rw-r--r--sys/contrib/openzfs/include/os/linux/kernel/linux/dcache_compat.h2
-rw-r--r--sys/contrib/openzfs/include/sys/vdev_rebuild.h1
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c18
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_diff.c4
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_impl.h1
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_mnttab.c70
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_pool.c2
-rw-r--r--sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c2
-rw-r--r--sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c16
-rw-r--r--sys/contrib/openzfs/man/man4/spl.413
-rw-r--r--sys/contrib/openzfs/man/man7/vdevprops.76
-rw-r--r--sys/contrib/openzfs/man/man7/zfsprops.715
-rw-r--r--sys/contrib/openzfs/module/nvpair/nvpair.c5
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_ctldir.c19
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c5
-rw-r--r--sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c16
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu.c10
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_objset.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dmu_send.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_bookmark.c18
-rw-r--r--sys/contrib/openzfs/module/zfs/dsl_dir.c2
-rw-r--r--sys/contrib/openzfs/module/zfs/vdev_rebuild.c12
-rw-r--r--sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h2
-rw-r--r--sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c8
-rw-r--r--sys/contrib/openzfs/tests/runfiles/common.run5
-rw-r--r--sys/contrib/openzfs/tests/runfiles/sanity.run2
-rwxr-xr-xsys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/.gitignore1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am4
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/libzfs_mnttab_cache_check.c107
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/cmd/threadsappend.c8
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg1
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am2
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh13
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/libzfs/libzfs_mnttab_cache.ksh26
-rwxr-xr-xsys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_max_blkid.ksh118
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib9
-rw-r--r--sys/modules/zfs/zfs_config.h7
-rw-r--r--sys/modules/zfs/zfs_gitrev.h2
47 files changed, 522 insertions, 107 deletions
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 f4e70c31c4cd..e63aece389c0 100755
--- a/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh
+++ b/sys/contrib/openzfs/.github/workflows/scripts/qemu-2-start.sh
@@ -88,6 +88,11 @@ case "$OS" in
OSv="fedora-unknown"
URL="https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2"
;;
+ fedora44)
+ OSNAME="Fedora 44"
+ OSv="fedora-unknown"
+ URL="https://download.fedoraproject.org/pub/fedora/linux/releases/44/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-44-1.7.x86_64.qcow2"
+ ;;
freebsd13-5r)
FreeBSD="13.5-RELEASE"
OSNAME="FreeBSD $FreeBSD"
@@ -103,6 +108,13 @@ case "$OS" in
URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI.raw.xz"
KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz"
;;
+ freebsd15-0r)
+ FreeBSD="15.0-RELEASE"
+ OSNAME="FreeBSD $FreeBSD"
+ OSv="freebsd15.0"
+ URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
+ KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz"
+ ;;
freebsd13-5s)
FreeBSD="13.5-STABLE"
OSNAME="FreeBSD $FreeBSD"
@@ -118,8 +130,8 @@ case "$OS" in
URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz"
;;
- freebsd15-0s)
- FreeBSD="15.0-STABLE"
+ freebsd15-1s)
+ FreeBSD="15.1-PRERELEASE"
OSNAME="FreeBSD $FreeBSD"
OSv="freebsd14.0"
URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz"
diff --git a/sys/contrib/openzfs/.github/workflows/zfs-qemu-packages.yml b/sys/contrib/openzfs/.github/workflows/zfs-qemu-packages.yml
index 88d85a06d975..c3a7397c6aef 100644
--- a/sys/contrib/openzfs/.github/workflows/zfs-qemu-packages.yml
+++ b/sys/contrib/openzfs/.github/workflows/zfs-qemu-packages.yml
@@ -58,7 +58,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: ['almalinux8', 'almalinux9', 'almalinux10', 'fedora42', 'fedora43']
+ os: ['almalinux8', 'almalinux9', 'almalinux10', 'fedora42', 'fedora43', 'fedora44']
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
diff --git a/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml b/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml
index f83b319a331f..4b4fd27543fd 100644
--- a/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml
+++ b/sys/contrib/openzfs/.github/workflows/zfs-qemu.yml
@@ -46,17 +46,17 @@ jobs:
case "$ci_type" in
quick)
- os_selection='["almalinux8", "almalinux9", "almalinux10", "debian12", "fedora42", "freebsd15-0s", "ubuntu24"]'
+ os_selection='["almalinux8", "almalinux9", "almalinux10", "debian12", "fedora42", "freebsd15-1s", "ubuntu24"]'
;;
linux)
- os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian11", "debian12", "debian13", "fedora42", "fedora43", "ubuntu22", "ubuntu24"]'
+ os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian11", "debian12", "debian13", "fedora42", "fedora43", "fedora44", "ubuntu22", "ubuntu24"]'
;;
freebsd)
- os_selection='["freebsd13-5r", "freebsd14-4r", "freebsd13-5s", "freebsd14-4s", "freebsd15-0s", "freebsd16-0c"]'
+ os_selection='["freebsd13-5r", "freebsd14-4r", "freebsd13-5s", "freebsd14-4s", "freebsd15-1s", "freebsd16-0c"]'
;;
*)
# default list
- os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora42", "fedora43", "freebsd14-4r", "freebsd15-0s", "freebsd16-0c", "ubuntu22", "ubuntu24"]'
+ os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora42", "fedora43", "fedora44", "freebsd14-4r", "freebsd15-1s", "freebsd16-0c", "ubuntu22", "ubuntu24"]'
;;
esac
@@ -99,7 +99,7 @@ jobs:
# misc: archlinux, tumbleweed
# FreeBSD variants of november 2025:
# FreeBSD Release: freebsd13-5r, freebsd14-4r, freebsd15-0r
- # FreeBSD Stable: freebsd13-5s, freebsd14-4s, freebsd15-0s
+ # FreeBSD Stable: freebsd13-5s, freebsd14-4s, freebsd15-1s
# FreeBSD Current: freebsd16-0c
os: ${{ fromJson(needs.test-config.outputs.test_os) }}
runs-on: ubuntu-24.04
diff --git a/sys/contrib/openzfs/cmd/zed/zed_event.c b/sys/contrib/openzfs/cmd/zed/zed_event.c
index ba7cba304b1d..e252e0999c18 100644
--- a/sys/contrib/openzfs/cmd/zed/zed_event.c
+++ b/sys/contrib/openzfs/cmd/zed/zed_event.c
@@ -238,7 +238,7 @@ _zed_event_value_is_hex(const char *name)
NULL
};
const char **pp;
- char *p;
+ const char *p;
if (!name)
return (0);
diff --git a/sys/contrib/openzfs/cmd/zfs/zfs_main.c b/sys/contrib/openzfs/cmd/zfs/zfs_main.c
index 631ddda5c6e6..4c21c92bcd2f 100644
--- a/sys/contrib/openzfs/cmd/zfs/zfs_main.c
+++ b/sys/contrib/openzfs/cmd/zfs/zfs_main.c
@@ -6867,7 +6867,7 @@ holds_callback(zfs_handle_t *zhp, void *data)
if (cbp->cb_recursive) {
const char *snapname;
- char *delim = strchr(zname, '@');
+ const char *delim = strchr(zname, '@');
if (delim == NULL)
return (0);
@@ -9417,6 +9417,7 @@ main(int argc, char **argv)
/*
* Run the appropriate command.
*/
+ libzfs_mnttab_cache(g_zfs, B_TRUE);
if (find_command_idx(cmdname, &i) == 0) {
current_command = &command_table[i];
ret = command_table[i].func(argc - 1, newargv + 1);
diff --git a/sys/contrib/openzfs/config/kernel-dentry-alias.m4 b/sys/contrib/openzfs/config/kernel-dentry-alias.m4
new file mode 100644
index 000000000000..0baf1a06d3ce
--- /dev/null
+++ b/sys/contrib/openzfs/config/kernel-dentry-alias.m4
@@ -0,0 +1,32 @@
+dnl # SPDX-License-Identifier: CDDL-1.0
+dnl #
+dnl # 7.1 API change
+dnl # d_u union in struct dentry is now anonmymous, so d_alias must be
+dnl # named directly
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_DENTRY_ALIAS_D_U], [
+ ZFS_LINUX_TEST_SRC([dentry_alias_d_u], [
+ #include <linux/fs.h>
+ #include <linux/dcache.h>
+ #include <linux/list.h>
+ ], [
+ struct inode *inode __attribute__ ((unused)) = NULL;
+ struct dentry *dentry __attribute__ ((unused)) = NULL;
+ hlist_for_each_entry(dentry, &inode->i_dentry,
+ d_u.d_alias) {
+ d_drop(dentry);
+ }
+ ])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_DENTRY_ALIAS_D_U], [
+ AC_MSG_CHECKING([whether dentry aliases are in d_u member])
+ ZFS_LINUX_TEST_RESULT([dentry_alias_d_u], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_DENTRY_D_U_ALIASES, 1,
+ [dentry aliases are in d_u member])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
diff --git a/sys/contrib/openzfs/config/kernel.m4 b/sys/contrib/openzfs/config/kernel.m4
index e1dba34e5dbe..b40e34d373f6 100644
--- a/sys/contrib/openzfs/config/kernel.m4
+++ b/sys/contrib/openzfs/config/kernel.m4
@@ -74,6 +74,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_SETATTR_PREPARE
ZFS_AC_KERNEL_SRC_INSERT_INODE_LOCKED
ZFS_AC_KERNEL_SRC_DENTRY
+ ZFS_AC_KERNEL_SRC_DENTRY_ALIAS_D_U
ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE
ZFS_AC_KERNEL_SRC_SECURITY_INODE
ZFS_AC_KERNEL_SRC_FS_CONTEXT
@@ -198,6 +199,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_SETATTR_PREPARE
ZFS_AC_KERNEL_INSERT_INODE_LOCKED
ZFS_AC_KERNEL_DENTRY
+ ZFS_AC_KERNEL_DENTRY_ALIAS_D_U
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
ZFS_AC_KERNEL_SECURITY_INODE
ZFS_AC_KERNEL_FS_CONTEXT
diff --git a/sys/contrib/openzfs/etc/systemd/system-generators/zfs-mount-generator.c b/sys/contrib/openzfs/etc/systemd/system-generators/zfs-mount-generator.c
index 7ad9ff61d8ee..bbd90a7048f7 100644
--- a/sys/contrib/openzfs/etc/systemd/system-generators/zfs-mount-generator.c
+++ b/sys/contrib/openzfs/etc/systemd/system-generators/zfs-mount-generator.c
@@ -202,6 +202,7 @@ line_worker(char *line, const char *cachefile)
void **tofree = tofree_all;
char *toktmp;
+ const char *toktmp2;
/* BEGIN CSTYLED */
const char *dataset = strtok_r(line, "\t", &toktmp);
char *p_mountpoint = strtok_r(NULL, "\t", &toktmp);
@@ -226,8 +227,8 @@ line_worker(char *line, const char *cachefile)
/* END CSTYLED */
size_t pool_len = strlen(dataset);
- if ((toktmp = strchr(dataset, '/')) != NULL)
- pool_len = toktmp - dataset;
+ if ((toktmp2 = strchr(dataset, '/')) != NULL)
+ pool_len = toktmp2 - dataset;
const char *pool = *(tofree++) = strndup(dataset, pool_len);
if (p_nbmand == NULL) {
diff --git a/sys/contrib/openzfs/include/os/linux/kernel/linux/dcache_compat.h b/sys/contrib/openzfs/include/os/linux/kernel/linux/dcache_compat.h
index f94dcda6175b..e27158926917 100644
--- a/sys/contrib/openzfs/include/os/linux/kernel/linux/dcache_compat.h
+++ b/sys/contrib/openzfs/include/os/linux/kernel/linux/dcache_compat.h
@@ -32,7 +32,9 @@
#define dname(dentry) ((char *)((dentry)->d_name.name))
#define dlen(dentry) ((int)((dentry)->d_name.len))
+#ifdef HAVE_DENTRY_D_U_ALIASES
#define d_alias d_u.d_alias
+#endif
#ifdef HAVE_MM_PAGE_FLAGS_STRUCT
/*
diff --git a/sys/contrib/openzfs/include/sys/vdev_rebuild.h b/sys/contrib/openzfs/include/sys/vdev_rebuild.h
index b787b1d5d993..8ecb30659434 100644
--- a/sys/contrib/openzfs/include/sys/vdev_rebuild.h
+++ b/sys/contrib/openzfs/include/sys/vdev_rebuild.h
@@ -70,6 +70,7 @@ typedef struct vdev_rebuild {
zfs_range_tree_t *vr_scan_tree;
kmutex_t vr_io_lock; /* inflight IO lock */
kcondvar_t vr_io_cv; /* inflight IO cv */
+ uint64_t vr_last_txg; /* last used txg */
/* In-core state and progress */
uint64_t vr_scan_offset[TXG_SIZE];
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c b/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c
index 923bbd995de5..ea316010629b 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_dataset.c
@@ -708,7 +708,7 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types)
{
zfs_handle_t *zhp;
char errbuf[ERRBUFLEN];
- char *bookp;
+ const char *bookp;
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
@@ -2958,7 +2958,7 @@ userquota_propname_decode(const char *propname, boolean_t zoned,
zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
{
zfs_userquota_prop_t type;
- char *cp;
+ const char *cp;
boolean_t isuser;
boolean_t isgroup;
boolean_t isproject;
@@ -4314,12 +4314,13 @@ zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
{
int ret = 0;
zfs_cmd_t zc = {"\0"};
- char *delim;
prop_changelist_t *cl = NULL;
char parent[ZFS_MAX_DATASET_NAME_LEN];
char property[ZFS_MAXPROPLEN];
libzfs_handle_t *hdl = zhp->zfs_hdl;
char errbuf[ERRBUFLEN];
+ const char *delim;
+ char *delim2;
/* if we have the same exact name, just return success */
if (strcmp(zhp->zfs_name, target) == 0)
@@ -4344,11 +4345,11 @@ zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
*/
(void) strlcpy(parent, zhp->zfs_name,
sizeof (parent));
- delim = strchr(parent, '@');
+ delim2 = strchr(parent, '@');
if (strchr(target, '@') == NULL)
- *(++delim) = '\0';
+ *(++delim2) = '\0';
else
- *delim = '\0';
+ *delim2 = '\0';
(void) strlcat(parent, target, sizeof (parent));
target = parent;
} else {
@@ -4369,6 +4370,7 @@ zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
} else {
+
if (flags.recursive) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"recursive rename must be a snapshot"));
@@ -4424,8 +4426,8 @@ zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
}
if (flags.recursive) {
char *parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
- delim = strchr(parentname, '@');
- *delim = '\0';
+ delim2 = strchr(parentname, '@');
+ *delim2 = '\0';
zfs_handle_t *zhrp = zfs_open(zhp->zfs_hdl, parentname,
ZFS_TYPE_DATASET);
free(parentname);
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_diff.c b/sys/contrib/openzfs/lib/libzfs/libzfs_diff.c
index 8e71dfa450b1..7f2130682118 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_diff.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_diff.c
@@ -550,8 +550,8 @@ get_snapshot_names(differ_info_t *di, const char *fromsnap,
const char *tosnap)
{
libzfs_handle_t *hdl = di->zhp->zfs_hdl;
- char *atptrf = NULL;
- char *atptrt = NULL;
+ const char *atptrf = NULL;
+ const char *atptrt = NULL;
int fdslen, fsnlen;
int tdslen, tsnlen;
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h b/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h
index 2ce8d49f08bc..6d7eca981d26 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_impl.h
@@ -66,6 +66,7 @@ struct libzfs_handle {
char *libfetch_load_error;
kmutex_t zh_mnttab_lock;
avl_tree_t zh_mnttab;
+ boolean_t zh_mnttab_cache_enabled;
};
struct zfs_handle {
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_mnttab.c b/sys/contrib/openzfs/lib/libzfs/libzfs_mnttab.c
index 473e3a7b45a1..75277066063c 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_mnttab.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_mnttab.c
@@ -81,34 +81,13 @@ mnttab_compare(const void *arg1, const void *arg2)
return (TREE_ISIGN(rv));
}
-void
-libzfs_mnttab_init(libzfs_handle_t *hdl)
-{
- mutex_init(&hdl->zh_mnttab_lock, NULL, MUTEX_DEFAULT, NULL);
- assert(avl_numnodes(&hdl->zh_mnttab) == 0);
- avl_create(&hdl->zh_mnttab, mnttab_compare,
- sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
-}
-
-void
-libzfs_mnttab_fini(libzfs_handle_t *hdl)
+static void
+mnttab_drop(libzfs_handle_t *hdl)
{
- void *cookie = NULL;
mnttab_node_t *mtn;
-
- while ((mtn = avl_destroy_nodes(&hdl->zh_mnttab, &cookie))
- != NULL)
+ void *cookie = NULL;
+ while ((mtn = avl_destroy_nodes(&hdl->zh_mnttab, &cookie)) != NULL)
mnttab_node_free(hdl, mtn);
-
- avl_destroy(&hdl->zh_mnttab);
- (void) mutex_destroy(&hdl->zh_mnttab_lock);
-}
-
-void
-libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
-{
- /* This is a no-op to preserve ABI backward compatibility. */
- (void) hdl, (void) enable;
}
static int
@@ -145,6 +124,33 @@ mnttab_update(libzfs_handle_t *hdl)
return (0);
}
+
+void
+libzfs_mnttab_init(libzfs_handle_t *hdl)
+{
+ mutex_init(&hdl->zh_mnttab_lock, NULL, MUTEX_DEFAULT, NULL);
+ assert(avl_numnodes(&hdl->zh_mnttab) == 0);
+ avl_create(&hdl->zh_mnttab, mnttab_compare,
+ sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
+ hdl->zh_mnttab_cache_enabled = B_FALSE;
+}
+
+void
+libzfs_mnttab_fini(libzfs_handle_t *hdl)
+{
+ mnttab_drop(hdl);
+ avl_destroy(&hdl->zh_mnttab);
+ (void) mutex_destroy(&hdl->zh_mnttab_lock);
+}
+
+void
+libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
+{
+ mutex_enter(&hdl->zh_mnttab_lock);
+ hdl->zh_mnttab_cache_enabled = enable;
+ mutex_exit(&hdl->zh_mnttab_lock);
+}
+
int
libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
struct mnttab *entry)
@@ -154,6 +160,9 @@ libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
int ret = ENOENT;
mutex_enter(&hdl->zh_mnttab_lock);
+ if (!hdl->zh_mnttab_cache_enabled)
+ mnttab_drop(hdl);
+
if (avl_numnodes(&hdl->zh_mnttab) == 0) {
int error;
@@ -180,6 +189,11 @@ libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
mnttab_node_t *mtn;
mutex_enter(&hdl->zh_mnttab_lock);
+ if (!hdl->zh_mnttab_cache_enabled) {
+ /* Don't bother; we're going to discard it anyway. */
+ mutex_exit(&hdl->zh_mnttab_lock);
+ return;
+ }
mtn = mnttab_node_alloc(hdl, special, mountp, mntopts);
@@ -202,6 +216,12 @@ libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
mnttab_node_t *ret;
mutex_enter(&hdl->zh_mnttab_lock);
+ if (!hdl->zh_mnttab_cache_enabled) {
+ /* Don't bother; we're going to discard it anyway. */
+ mutex_exit(&hdl->zh_mnttab_lock);
+ return;
+ }
+
find.mtn_mt.mnt_special = (char *)fsname;
if ((ret = avl_find(&hdl->zh_mnttab, (void *)&find, NULL)) != NULL) {
avl_remove(&hdl->zh_mnttab, ret);
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c b/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
index 7cd6a768084b..0b015d8bce64 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_pool.c
@@ -640,7 +640,7 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
prop = zpool_name_to_prop(propname);
if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
int err;
- char *fname = strchr(propname, '@') + 1;
+ const char *fname = strchr(propname, '@') + 1;
err = zfeature_lookup_name(fname, NULL);
if (err != 0) {
diff --git a/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c b/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
index 18130a34fea8..f55d0c646bdf 100644
--- a/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
+++ b/sys/contrib/openzfs/lib/libzfs/libzfs_sendrecv.c
@@ -2697,7 +2697,7 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd,
char bookname[ZFS_MAX_DATASET_NAME_LEN];
nvlist_t *redact_snaps;
zfs_handle_t *book_zhp;
- char *at, *pound;
+ const char *at, *pound;
int dsnamelen;
pound = strchr(redactbook, '#');
diff --git a/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c b/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c
index 8ed062bf9b37..64e05f52d95e 100644
--- a/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c
+++ b/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_device_path_os.c
@@ -218,7 +218,8 @@ zfs_get_pci_slots_sys_path(const char *dev_name)
char *address2 = NULL;
char *path = NULL;
char buf[MAXPATHLEN];
- char *tmp;
+ const char *tmp;
+ char *tmp2;
/* If they preface 'dev' with a path (like "/dev") then strip it off */
tmp = strrchr(dev_name, '/');
@@ -240,9 +241,9 @@ zfs_get_pci_slots_sys_path(const char *dev_name)
* be "0000:01:00.0" while /sys/bus/pci/slots/0/address will be
* "0000:01:00". Just NULL terminate at the '.' so they match.
*/
- tmp = strrchr(address1, '.');
- if (tmp != NULL)
- *tmp = '\0';
+ tmp2 = strrchr(address1, '.');
+ if (tmp2 != NULL)
+ *tmp2 = '\0';
dp = opendir("/sys/bus/pci/slots/");
if (dp == NULL) {
@@ -311,6 +312,7 @@ zfs_get_enclosure_sysfs_path(const char *dev_name)
DIR *dp = NULL;
struct dirent *ep;
char buf[MAXPATHLEN];
+ const char *tmp0;
char *tmp1 = NULL;
char *tmp2 = NULL;
char *tmp3 = NULL;
@@ -322,9 +324,9 @@ zfs_get_enclosure_sysfs_path(const char *dev_name)
return (NULL);
/* If they preface 'dev' with a path (like "/dev") then strip it off */
- tmp1 = strrchr(dev_name, '/');
- if (tmp1 != NULL)
- dev_name = tmp1 + 1; /* +1 since we want the chr after '/' */
+ tmp0 = strrchr(dev_name, '/');
+ if (tmp0 != NULL)
+ dev_name = tmp0 + 1; /* +1 since we want the chr after '/' */
tmpsize = asprintf(&tmp1, "/sys/block/%s/device", dev_name);
if (tmpsize == -1 || tmp1 == NULL) {
diff --git a/sys/contrib/openzfs/man/man4/spl.4 b/sys/contrib/openzfs/man/man4/spl.4
index 61dfe42e463d..2ca69e929778 100644
--- a/sys/contrib/openzfs/man/man4/spl.4
+++ b/sys/contrib/openzfs/man/man4/spl.4
@@ -130,6 +130,19 @@ When not enabled, the thread is halted to facilitate further debugging.
.Pp
Set to a non-zero value to enable.
.
+.It Sy spl_schedule_hrtimeout_slack_us Ns = Ns Sy 0 Pq uint
+Slack value in microseconds passed to
+.Fn schedule_hrtimeout_range
+when a condition variable times out.
+A non-zero value enforces the kernel coalesce the wakeup with other timers
+to reduce wakeup count, at the cost of some additional sleep duration.
+The maximum is
+.Sy 1000 ,
+as defined by
+.Sy MAX_HRTIMEOUT_SLACK_US .
+.Pp
+Linux-only.
+.
.It Sy spl_taskq_kick Ns = Ns Sy 0 Pq uint
Kick stuck taskq to spawn threads.
When writing a non-zero value to it, it will scan all the taskqs.
diff --git a/sys/contrib/openzfs/man/man7/vdevprops.7 b/sys/contrib/openzfs/man/man7/vdevprops.7
index bb5fec65eff6..b45128dd9242 100644
--- a/sys/contrib/openzfs/man/man7/vdevprops.7
+++ b/sys/contrib/openzfs/man/man7/vdevprops.7
@@ -134,6 +134,12 @@ The number of I/O operations of each type performed by this vdev
The cumulative size of all operations of each type performed by this vdev
.It Sy removing
If this device is currently being removed from the pool
+.It Sy raidz_expanding
+Set while a
+.Nm zpool Cm attach
+expansion is in progress on this RAID-Z vdev; cleared on completion.
+See
+.Xr zpool-attach 8 .
.It Sy trim_support
Indicates if a leaf device supports trim operations.
.El
diff --git a/sys/contrib/openzfs/man/man7/zfsprops.7 b/sys/contrib/openzfs/man/man7/zfsprops.7
index 183e6ea95745..302dffa0e6d1 100644
--- a/sys/contrib/openzfs/man/man7/zfsprops.7
+++ b/sys/contrib/openzfs/man/man7/zfsprops.7
@@ -1360,6 +1360,21 @@ This was only supported by Linux prior to 5.15, and was buggy there,
and is not supported by
.Fx .
On Solaris it's used for SMB clients.
+.It Sy longname Ns = Ns Sy on Ns | Ns Sy off
+Controls support for filenames longer than 255 bytes, up to 1023 bytes.
+The default is
+.Sy off .
+Setting this property to
+.Sy on
+activates the
+.Sy longname
+pool feature, which must be enabled
+.Po see
+.Xr zpool-features 7
+.Pc .
+Once a file with a long name is created, the feature becomes active and
+the pool can no longer be imported by an OpenZFS implementation that does
+not support it.
.It Sy overlay Ns = Ns Sy on Ns | Ns Sy off
Allow mounting on a busy directory or a directory which already contains
files or directories.
diff --git a/sys/contrib/openzfs/module/nvpair/nvpair.c b/sys/contrib/openzfs/module/nvpair/nvpair.c
index 14fbddb60f6b..07ac102145e2 100644
--- a/sys/contrib/openzfs/module/nvpair/nvpair.c
+++ b/sys/contrib/openzfs/module/nvpair/nvpair.c
@@ -1923,8 +1923,9 @@ nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
{
nvpair_t *nvp;
const char *np;
- char *sepp = NULL;
- char *idxp, *idxep;
+ const char *sepp = NULL;
+ const char *idxp;
+ char *idxep;
nvlist_t **nva;
long idx = 0;
int n;
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_ctldir.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_ctldir.c
index c73ef86df4dc..767272177fb7 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_ctldir.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_ctldir.c
@@ -1138,15 +1138,28 @@ zfsctl_snapshot_unmount(const char *snapname, int flags)
cv_wait(&se->se_cv, &se->se_mtx);
mutex_exit(&se->se_mtx);
- exportfs_flush();
-
if (flags & MNT_FORCE)
argv[4] = "-fn";
argv[5] = se->se_path;
dprintf("unmount; path=%s\n", se->se_path);
error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
- zfsctl_snapshot_rele(se);
+ /*
+ * The kernel's NFS export cache can hold references to the
+ * snapshot mountpoint and cause umount to fail. ZFS cannot
+ * invalidate individual entries because the relevant kernel
+ * APIs are exported GPL-only, so we issue a global flush
+ * instead. To avoid impacting unrelated snapshots, the flush
+ * runs only on umount failure. Not perfect, but better than
+ * flushing unconditionally.
+ */
+ if (error) {
+ exportfs_flush();
+ error = call_usermodehelper(argv[0], argv, envp,
+ UMH_WAIT_PROC);
+ }
+
+ zfsctl_snapshot_rele(se);
/*
* The umount system utility will return 256 on error. We must
diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c
index 9c0d92551843..d7b502429923 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vfsops.c
@@ -953,11 +953,12 @@ objs:
int
zfs_statvfs(struct inode *ip, struct kstatfs *statp)
{
+ znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
uint64_t refdbytes, availbytes, usedobjs, availobjs;
int err = 0;
- if ((err = zfs_enter(zfsvfs, FTAG)) != 0)
+ if ((err = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
return (err);
dmu_objset_space(zfsvfs->z_os,
@@ -1013,8 +1014,6 @@ zfs_statvfs(struct inode *ip, struct kstatfs *statp)
if (dmu_objset_projectquota_enabled(zfsvfs->z_os) &&
dmu_objset_projectquota_present(zfsvfs->z_os)) {
- znode_t *zp = ITOZ(ip);
-
if (zp->z_pflags & ZFS_PROJINHERIT && zp->z_projid &&
zpl_is_valid_projid(zp->z_projid))
err = zfs_statfs_project(zfsvfs, zp, statp, bshift);
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 ffe227796f0a..6d57bff56540 100644
--- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
+++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c
@@ -673,6 +673,8 @@ static long
zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
{
cred_t *cr = CRED();
+ znode_t *zp = ITOZ(ip);
+ zfsvfs_t *zfsvfs = ITOZSB(ip);
loff_t olen;
fstrans_cookie_t cookie;
int error = 0;
@@ -706,7 +708,7 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
bf.l_len = len;
bf.l_pid = 0;
- error = -zfs_space(ITOZ(ip), F_FREESP, &bf, O_RDWR, offset, cr);
+ error = -zfs_space(zp, F_FREESP, &bf, O_RDWR, offset, cr);
} else if ((mode & ~FALLOC_FL_KEEP_SIZE) == 0) {
unsigned int percent = zfs_fallocate_reserve_percent;
struct kstatfs statfs;
@@ -721,7 +723,7 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
* Use zfs_statvfs() instead of dmu_objset_space() since it
* also checks project quota limits, which are relevant here.
*/
- error = zfs_statvfs(ip, &statfs);
+ error = -zfs_statvfs(ip, &statfs);
if (error)
goto out_unmark;
@@ -734,8 +736,14 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
error = -ENOSPC;
goto out_unmark;
}
- if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > olen)
- error = zfs_freesp(ITOZ(ip), offset + len, 0, 0, FALSE);
+ if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > olen) {
+ error = zpl_enter_verify_zp(zfsvfs, zp, FTAG);
+ if (error)
+ goto out_unmark;
+
+ error = -zfs_freesp(zp, offset + len, 0, 0, FALSE);
+ zfs_exit(zfsvfs, FTAG);
+ }
}
out_unmark:
spl_fstrans_unmark(cookie);
diff --git a/sys/contrib/openzfs/module/zfs/dmu.c b/sys/contrib/openzfs/module/zfs/dmu.c
index 0f40164ecc95..d709f9a34aff 100644
--- a/sys/contrib/openzfs/module/zfs/dmu.c
+++ b/sys/contrib/openzfs/module/zfs/dmu.c
@@ -966,8 +966,14 @@ dmu_evict_range(objset_t *os, uint64_t object, uint64_t offset, uint64_t len)
* access patterns are rare.
*/
rw_enter(&dn->dn_struct_rwlock, RW_READER);
- uint64_t start = dbuf_whichblock(dn, 0, offset);
- uint64_t end = dbuf_whichblock(dn, 0, offset + len);
+ uint64_t start, end;
+ if (dn->dn_datablkshift != 0) {
+ start = dbuf_whichblock(dn, 0, offset);
+ end = dbuf_whichblock(dn, 0, offset + len);
+ } else {
+ start = (offset >= dn->dn_datablksz);
+ end = (offset + len >= dn->dn_datablksz);
+ }
if (end > start)
dbuf_evict_range(dn, start, end - 1);
rw_exit(&dn->dn_struct_rwlock);
diff --git a/sys/contrib/openzfs/module/zfs/dmu_objset.c b/sys/contrib/openzfs/module/zfs/dmu_objset.c
index ed81647bcfa3..4919ead3cea6 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_objset.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_objset.c
@@ -3011,7 +3011,7 @@ dmu_objset_get_user(objset_t *os)
int
dmu_fsname(const char *snapname, char *buf)
{
- char *atp = strchr(snapname, '@');
+ const char *atp = strchr(snapname, '@');
if (atp == NULL)
return (SET_ERROR(EINVAL));
if (atp - snapname >= ZFS_MAX_DATASET_NAME_LEN)
diff --git a/sys/contrib/openzfs/module/zfs/dmu_send.c b/sys/contrib/openzfs/module/zfs/dmu_send.c
index 8ecb99d5f57c..4c354722e4f8 100644
--- a/sys/contrib/openzfs/module/zfs/dmu_send.c
+++ b/sys/contrib/openzfs/module/zfs/dmu_send.c
@@ -1844,7 +1844,7 @@ send_reader_thread(void *arg)
continue;
}
uint64_t file_max =
- MIN(dn->dn_maxblkid, range->end_blkid);
+ MIN(dn->dn_maxblkid + 1, range->end_blkid);
/*
* The object exists, so we need to try to find the
* blkptr for each block in the range we're processing.
diff --git a/sys/contrib/openzfs/module/zfs/dsl_bookmark.c b/sys/contrib/openzfs/module/zfs/dsl_bookmark.c
index 8533657ad03b..4ffd75ceace9 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_bookmark.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_bookmark.c
@@ -39,10 +39,10 @@
static int
dsl_bookmark_hold_ds(dsl_pool_t *dp, const char *fullname,
- dsl_dataset_t **dsp, const void *tag, char **shortnamep)
+ dsl_dataset_t **dsp, const void *tag, const char **shortnamep)
{
char buf[ZFS_MAX_DATASET_NAME_LEN];
- char *hashp;
+ const char *hashp;
if (strlen(fullname) >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG));
@@ -105,7 +105,7 @@ int
dsl_bookmark_lookup(dsl_pool_t *dp, const char *fullname,
dsl_dataset_t *later_ds, zfs_bookmark_phys_t *bmp)
{
- char *shortname;
+ const char *shortname;
dsl_dataset_t *ds;
int error;
@@ -219,7 +219,7 @@ dsl_bookmark_create_check_impl(dsl_pool_t *dp,
int error;
dsl_dataset_t *newbm_ds;
- char *newbm_short;
+ const char *newbm_short;
zfs_bookmark_phys_t bmark_phys;
error = dsl_bookmark_hold_ds(dp, newbm, &newbm_ds, FTAG, &newbm_short);
@@ -329,7 +329,7 @@ dsl_bookmark_create_check(void *arg, dmu_tx_t *tx)
}
static dsl_bookmark_node_t *
-dsl_bookmark_node_alloc(char *shortname)
+dsl_bookmark_node_alloc(const char *shortname)
{
dsl_bookmark_node_t *dbn = kmem_alloc(sizeof (*dbn), KM_SLEEP);
dbn->dbn_name = spa_strdup(shortname);
@@ -445,7 +445,7 @@ dsl_bookmark_create_sync_impl_snap(const char *bookmark, const char *snapshot,
dsl_pool_t *dp = dmu_tx_pool(tx);
objset_t *mos = dp->dp_meta_objset;
dsl_dataset_t *snapds, *bmark_fs;
- char *shortname;
+ const char *shortname;
boolean_t bookmark_redacted;
uint64_t *dsredactsnaps;
uint64_t dsnumsnaps;
@@ -535,7 +535,7 @@ dsl_bookmark_create_sync_impl_book(
{
dsl_pool_t *dp = dmu_tx_pool(tx);
dsl_dataset_t *bmark_fs_source, *bmark_fs_new;
- char *source_shortname, *new_shortname;
+ const char *source_shortname, *new_shortname;
zfs_bookmark_phys_t source_phys;
VERIFY0(dsl_bookmark_hold_ds(dp, source_name, &bmark_fs_source, FTAG,
@@ -1105,7 +1105,7 @@ dsl_bookmark_destroy_check(void *arg, dmu_tx_t *tx)
dsl_dataset_t *ds;
zfs_bookmark_phys_t bm;
int error;
- char *shortname;
+ const char *shortname;
error = dsl_bookmark_hold_ds(dp, fullname, &ds,
FTAG, &shortname);
@@ -1161,7 +1161,7 @@ dsl_bookmark_destroy_sync(void *arg, dmu_tx_t *tx)
for (nvpair_t *pair = nvlist_next_nvpair(dbda->dbda_success, NULL);
pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_success, pair)) {
dsl_dataset_t *ds;
- char *shortname;
+ const char *shortname;
uint64_t zap_cnt;
VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
diff --git a/sys/contrib/openzfs/module/zfs/dsl_dir.c b/sys/contrib/openzfs/module/zfs/dsl_dir.c
index 6ce1890cfea1..2253b868b53c 100644
--- a/sys/contrib/openzfs/module/zfs/dsl_dir.c
+++ b/sys/contrib/openzfs/module/zfs/dsl_dir.c
@@ -417,7 +417,7 @@ dsl_dir_namelen(dsl_dir_t *dd)
static int
getcomponent(const char *path, char *component, const char **nextp)
{
- char *p;
+ const char *p;
if ((path == NULL) || (path[0] == '\0'))
return (SET_ERROR(ENOENT));
diff --git a/sys/contrib/openzfs/module/zfs/vdev_rebuild.c b/sys/contrib/openzfs/module/zfs/vdev_rebuild.c
index 4fe6dc9d6fbb..de691f73e939 100644
--- a/sys/contrib/openzfs/module/zfs/vdev_rebuild.c
+++ b/sys/contrib/openzfs/module/zfs/vdev_rebuild.c
@@ -593,6 +593,7 @@ vdev_rebuild_range(vdev_rebuild_t *vr, uint64_t start, uint64_t size)
dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
VERIFY0(dmu_tx_assign(tx, DMU_TX_WAIT | DMU_TX_SUSPEND));
uint64_t txg = dmu_tx_get_txg(tx);
+ vr->vr_last_txg = txg;
spa_config_enter(spa, SCL_STATE_ALL, vd, RW_READER);
mutex_enter(&vd->vdev_rebuild_lock);
@@ -824,6 +825,7 @@ vdev_rebuild_thread(void *arg)
uint64_t limit = (arc_c_max / 2) / MAX(rvd->vdev_children, 1);
vr->vr_bytes_inflight_max = MIN(limit, MAX(1ULL << 20,
zfs_rebuild_vdev_limit * vd->vdev_children));
+ vr->vr_last_txg = 0;
/*
* Removal of vdevs from the vdev tree may eliminate the need
@@ -910,8 +912,16 @@ vdev_rebuild_thread(void *arg)
error = vdev_rebuild_ranges(vr);
zfs_range_tree_vacate(vr->vr_scan_tree, NULL, NULL);
- spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+ /*
+ * Allow rebuilt ranges to be sync-ed before enabling metaslab
+ * to avoid any interfering allocations. Otherwise, we might
+ * see checksum errors after scrub.
+ */
+ if (vr->vr_last_txg != 0)
+ txg_wait_synced(dp, vr->vr_last_txg);
+
metaslab_enable(msp, B_FALSE, B_FALSE);
+ spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
if (error != 0)
break;
diff --git a/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h b/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h
index b7ff1e9b0923..614d996ab619 100644
--- a/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h
+++ b/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h
@@ -33,6 +33,8 @@
* Copyright (c) 2020, Sebastian Gottschall
*/
+#define _ZSTD_COMPAT_WRAPPER_H
+
/*
* This wrapper fixes a problem, in case the ZFS filesystem driver, is compiled
* statically into the kernel.
diff --git a/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c b/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c
index dfbe6f635627..90b9fe00fece 100644
--- a/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c
+++ b/sys/contrib/openzfs/module/zstd/lib/common/zstd_common.c
@@ -9,7 +9,9 @@
* You may select, at your option, one of the above-listed licenses.
*/
-
+#ifdef _ZSTD_COMPAT_WRAPPER_H
+#undef ZSTD_isError /* defined within zstd_internal.h */
+#endif
/*-*************************************
* Dependencies
@@ -34,8 +36,8 @@ const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; }
/*! ZSTD_isError() :
* tells if a return value is an error code
* symbol is required for external callers */
-#if !defined(_STANDALONE)
-unsigned ZSTD_isError(size_t code) __asm__("zfs_ZSTD_isError");
+#ifdef _ZSTD_COMPAT_WRAPPER_H
+#define ZSTD_isError zfs_ZSTD_isError
#endif
unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
diff --git a/sys/contrib/openzfs/tests/runfiles/common.run b/sys/contrib/openzfs/tests/runfiles/common.run
index 63913663a7b2..4c7e4e85ec00 100644
--- a/sys/contrib/openzfs/tests/runfiles/common.run
+++ b/sys/contrib/openzfs/tests/runfiles/common.run
@@ -906,7 +906,8 @@ tags = ['functional', 'quota']
[tests/functional/redacted_send]
tests = ['redacted_compressed', 'redacted_contents', 'redacted_deleted',
'redacted_disabled_feature', 'redacted_embedded', 'redacted_holes',
- 'redacted_incrementals', 'redacted_largeblocks', 'redacted_many_clones',
+ 'redacted_incrementals', 'redacted_largeblocks', 'redacted_max_blkid',
+ 'redacted_many_clones',
'redacted_mixed_recsize', 'redacted_mounts', 'redacted_negative',
'redacted_origin', 'redacted_panic', 'redacted_props', 'redacted_resume',
'redacted_size', 'redacted_volume']
@@ -1150,7 +1151,7 @@ tests = ['zvol_swap_001_pos', 'zvol_swap_002_pos', 'zvol_swap_004_pos']
tags = ['functional', 'zvol', 'zvol_swap']
[tests/functional/libzfs]
-tests = ['many_fds', 'libzfs_input']
+tests = ['many_fds', 'libzfs_input', 'libzfs_mnttab_cache']
tags = ['functional', 'libzfs']
[tests/functional/log_spacemap]
diff --git a/sys/contrib/openzfs/tests/runfiles/sanity.run b/sys/contrib/openzfs/tests/runfiles/sanity.run
index ca16bee67dda..936f2bcc32be 100644
--- a/sys/contrib/openzfs/tests/runfiles/sanity.run
+++ b/sys/contrib/openzfs/tests/runfiles/sanity.run
@@ -466,7 +466,7 @@ tests = ['large_files_001_pos', 'large_files_002_pos']
tags = ['functional', 'large_files']
[tests/functional/libzfs]
-tests = ['many_fds', 'libzfs_input']
+tests = ['many_fds', 'libzfs_input', 'libzfs_mnttab_cache']
tags = ['functional', 'libzfs']
[tests/functional/limits]
diff --git a/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in b/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
index 22da0fc5cc13..29d2760ccb8f 100755
--- a/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
+++ b/sys/contrib/openzfs/tests/test-runner/bin/zts-report.py.in
@@ -201,7 +201,6 @@ elif sys.platform.startswith('linux'):
# reasons listed above can be used.
#
maybe = {
- 'append/threadsappend_001_pos': ['FAIL', 6136],
'chattr/setup': ['SKIP', exec_reason],
'crtime/crtime_001_pos': ['SKIP', statx_reason],
'cli_root/zdb/zdb_006_pos': ['FAIL', known_reason],
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/.gitignore b/sys/contrib/openzfs/tests/zfs-tests/cmd/.gitignore
index 4bdca0acf52b..c0785d9a28e8 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/.gitignore
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/.gitignore
@@ -18,6 +18,7 @@
/getversion
/largest_file
/libzfs_input_check
+/libzfs_mnttab_cache_check
/manipulate_user_buffer
/mkbusy
/mkfile
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am
index c4155ca3cacd..9f92310985e7 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/Makefile.am
@@ -66,6 +66,10 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/libzfs_input_check
libzfs_core.la \
libnvpair.la
+scripts_zfs_tests_bin_PROGRAMS += %D%/libzfs_mnttab_cache_check
+%C%_libzfs_mnttab_cache_check_LDADD = \
+ libzfs.la
+
scripts_zfs_tests_bin_PROGRAMS += %D%/manipulate_user_buffer
%C%_manipulate_user_buffer_LDADD = -lpthread
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/libzfs_mnttab_cache_check.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/libzfs_mnttab_cache_check.c
new file mode 100644
index 000000000000..661c5ce43f66
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/libzfs_mnttab_cache_check.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: CDDL-1.0
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2026 by Delphix. All rights reserved.
+ */
+
+/*
+ * libzfs_mnttab_cache_check.c
+ *
+ * Tests that libzfs_mnttab_cache(hdl, B_FALSE) does indeed disable the
+ * per-handle mnttab cache. It does this by adding a fake entry to it, then
+ * trying to read the status of a known-mounted dataset from it.
+ *
+ * As currently implemented, when enabled, libzfs_mnttab_find() assumes the
+ * cache is correct and up to date if it has any entries in it at all. So by
+ * putting something in it before searching, the initial load from /etc/mtab
+ * never happens, and the real mounted datasets are never seen.
+ *
+ * When disabled, the entire cache is discarded and reloaded on every lookup,
+ * so the fake entry will disappear and the real state will be found correctly.
+ * to date if it has any entries in it at all.
+ *
+ * Run (as a user that can read /etc/mtab):
+ * ./libzfs_mnttab_cache_check <name-of-any-currently-mounted-zfs-dataset>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mnttab.h>
+#include <libzfs.h>
+
+int
+main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr,
+ "usage: %s <currently-mounted-zfs-dataset>\n", argv[0]);
+ return (2);
+ }
+ const char *real_ds = argv[1];
+
+ libzfs_handle_t *hdl = libzfs_init();
+ if (hdl == NULL) {
+ fprintf(stderr, "libzfs_init failed\n");
+ return (1);
+ }
+
+ /* Ask libzfs to disable the per-handle mnttab cache. */
+ libzfs_mnttab_cache(hdl, B_FALSE);
+
+ /*
+ * Stand-in for what zfs_mount() does internally on every successful
+ * mount: zfs_mount_at() calls libzfs_mnttab_add(hdl, ...) after
+ * do_mount(). In a real consumer, this happens implicitly; we call it
+ * directly here so the reproducer doesn't need root or a mountable
+ * dataset.
+ */
+ libzfs_mnttab_add(hdl, "fake/dataset", "/fake/mountpoint", "rw");
+
+ /*
+ * Now query ZFS_PROP_MOUNTED on a real, currently-mounted dataset.
+ * This is the standard libzfs API a consumer uses to check mount
+ * state. Internally it calls libzfs_mnttab_find().
+ */
+ zfs_handle_t *zhp = zfs_open(hdl, real_ds, ZFS_TYPE_FILESYSTEM);
+ if (zhp == NULL) {
+ fprintf(stderr, "zfs_open(%s) failed\n", real_ds);
+ libzfs_fini(hdl);
+ return (1);
+ }
+
+ uint64_t mounted = zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED);
+ zfs_close(zhp);
+
+ int rc;
+ if (mounted) {
+ printf("OK: ZFS_PROP_MOUNTED reports %s as mounted\n", real_ds);
+ rc = 0;
+ } else {
+ printf("BUG: ZFS_PROP_MOUNTED reports %s as NOT mounted\n",
+ real_ds);
+ printf(" but %s IS mounted (see /etc/mtab and "
+ "`zfs get mounted`).\n", real_ds);
+ printf(" libzfs_mnttab_cache(hdl, B_FALSE) did not "
+ "actually disable the cache.\n");
+ rc = 1;
+ }
+
+ libzfs_fini(hdl);
+ return (rc);
+}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/cmd/threadsappend.c b/sys/contrib/openzfs/tests/zfs-tests/cmd/threadsappend.c
index bdbb2881f529..ed0d74c3c279 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/cmd/threadsappend.c
+++ b/sys/contrib/openzfs/tests/zfs-tests/cmd/threadsappend.c
@@ -87,7 +87,7 @@ usage(void)
int
main(int argc, char **argv)
{
- pthread_t tid;
+ pthread_t tid[2];
int ret = 0;
long ncpus = 0;
int i;
@@ -120,7 +120,7 @@ main(int argc, char **argv)
}
for (i = 0; i < 2; i++) {
- ret = pthread_create(&tid, NULL, go, (void *)&i);
+ ret = pthread_create(&tid[i], NULL, go, (void *)&i);
if (ret != 0) {
(void) fprintf(stderr,
"zfs_threadsappend: thr_create(#%d) "
@@ -129,8 +129,8 @@ main(int argc, char **argv)
}
}
- while (pthread_join(tid, NULL) == 0)
- continue;
+ for (i = 0; i < 2; i++)
+ (void) pthread_join(tid[i], NULL);
return (0);
}
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg b/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
index a52cacec224a..19dbb5202c3c 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/commands.cfg
@@ -202,6 +202,7 @@ export ZFSTEST_FILES_COMMON='badsend
get_diff
getversion
largest_file
+ libzfs_mnttab_cache_check
libzfs_input_check
manipulate_user_buffer
mkbusy
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
index 3d98f43f848d..c4bcfea55955 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/Makefile.am
@@ -1700,6 +1700,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/largest_pool/largest_pool_001_pos.ksh \
functional/libzfs/cleanup.ksh \
functional/libzfs/libzfs_input.ksh \
+ functional/libzfs/libzfs_mnttab_cache.ksh \
functional/libzfs/setup.ksh \
functional/limits/cleanup.ksh \
functional/limits/filesystem_count.ksh \
@@ -1898,6 +1899,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/redacted_send/redacted_holes.ksh \
functional/redacted_send/redacted_incrementals.ksh \
functional/redacted_send/redacted_largeblocks.ksh \
+ functional/redacted_send/redacted_max_blkid.ksh \
functional/redacted_send/redacted_many_clones.ksh \
functional/redacted_send/redacted_mixed_recsize.ksh \
functional/redacted_send/redacted_mounts.ksh \
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh
index b19f576adcf4..53f3ad999d3b 100755
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/fadvise/fadvise_dontneed.ksh
@@ -32,11 +32,13 @@
# 2. Record cache_count from dbufstats
# 3. Call file_fadvise with POSIX_FADV_DONTNEED on the file
# 4. Verify that cache_count decreased
+# 5. Sanity-check eviction for single-block files.
#
verify_runnable "global"
-FILE=$TESTDIR/$TESTFILE0
+FILE0=$TESTDIR/$TESTFILE0
+FILE1=$TESTDIR/$TESTFILE1
BLKSZ=$(get_prop recordsize $TESTPOOL)
function cleanup
@@ -48,16 +50,21 @@ log_assert "Ensure POSIX_FADV_DONTNEED evicts data from the dbuf cache"
log_onexit cleanup
-log_must file_write -o create -f $FILE -b $BLKSZ -c 100
+log_must file_write -o create -f $FILE0 -b $BLKSZ -c 100
sync_pool $TESTPOOL
evicts1=$(kstat dbufstats.cache_count)
-log_must file_fadvise -f $FILE -a POSIX_FADV_DONTNEED
+log_must file_fadvise -f $FILE0 -a POSIX_FADV_DONTNEED
evicts2=$(kstat dbufstats.cache_count)
log_note "cache_count before=$evicts1 after=$evicts2"
log_must [ $evicts1 -gt $evicts2 ]
+log_must file_write -o create -f $FILE1 -b 12000 -c 1
+sync_pool $TESTPOOL
+
+log_must file_fadvise -f $FILE1 -a POSIX_FADV_DONTNEED
+
log_pass "POSIX_FADV_DONTNEED evicts data from the dbuf cache"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/libzfs/libzfs_mnttab_cache.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/libzfs/libzfs_mnttab_cache.ksh
new file mode 100755
index 000000000000..2459e364c1d7
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/libzfs/libzfs_mnttab_cache.ksh
@@ -0,0 +1,26 @@
+#!/bin/ksh -p
+# SPDX-License-Identifier: CDDL-1.0
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2026, TrueNAS.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_assert "libzfs mnttab cache works as expected"
+
+log_must libzfs_mnttab_cache_check $TESTPOOL/$TESTFS
+
+log_pass "libzfs mnttab cache works as expected"
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_max_blkid.ksh b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_max_blkid.ksh
new file mode 100755
index 000000000000..13820b470222
--- /dev/null
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redacted_send/redacted_max_blkid.ksh
@@ -0,0 +1,118 @@
+#!/bin/ksh
+# SPDX-License-Identifier: CDDL-1.0
+
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2026 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/redacted_send/redacted.kshlib
+
+#
+# Description:
+# Verify that an incremental send from a redaction bookmark correctly sends
+# the last block (dn_maxblkid) of a file through the PREVIOUSLY_REDACTED
+# path.
+#
+# Regression test for an off-by-one bug in the PREVIOUSLY_REDACTED handler
+# in send_reader_thread(). file_max was computed as:
+#
+# MIN(dn->dn_maxblkid, range->end_blkid)
+#
+# dn_maxblkid is an inclusive maximum block ID while range->end_blkid is
+# exclusive (one past the last block). Mixing these in MIN() caused the
+# loop condition "blkid < file_max" to skip block dn_maxblkid, silently
+# dropping the last block of any file whose last block was in the redaction
+# list. The block remained as zeros on the receiver even though ZFS
+# reported the send and receive as successful.
+#
+# Strategy:
+# 1. Create a dataset with a 16-block file of random data and snapshot it.
+# 2. Create a clone (redact_clone) that overwrites only the last block
+# (block 15, i.e., dn_maxblkid).
+# 3. Redact the base snapshot using redact_clone; block 15 enters the
+# redaction list.
+# 4. Create a second clone (send_clone) of the base snapshot that does NOT
+# modify block 15. Because block 15 in send_clone has birth <=
+# snap.creation_txg the TO traversal thread skips it; it must be sent
+# via the PREVIOUSLY_REDACTED path.
+# 5. Redacted-send the base snapshot to the receiver (block 15 = zeros).
+# 6. Incrementally send send_clone from the redaction bookmark; block 15
+# must be filled in by the PREVIOUSLY_REDACTED handler.
+# 7. Verify that block 15 on the receiver matches the original.
+#
+
+typeset ds_name="max_blkid"
+typeset sendfs="$POOL/$ds_name"
+typeset redact_clone="$POOL/${ds_name}_redact"
+typeset send_clone="$POOL/${ds_name}_send"
+typeset recvfs="$POOL2/$ds_name"
+typeset recv_clone="$POOL2/${ds_name}_send"
+typeset tmpdir="$(get_prop mountpoint $POOL)/tmp"
+typeset stream=$(mktemp $tmpdir/stream.XXXX)
+
+log_onexit redacted_cleanup $sendfs $recvfs $recv_clone
+
+# Create a dataset with a 16-block file.
+log_must zfs create $sendfs
+typeset mntpnt=$(get_prop mountpoint $sendfs)
+typeset bs=$(get_prop recsize $sendfs)
+log_must dd if=/dev/urandom of=$mntpnt/f1 bs=$bs count=16
+
+# Take the base snapshot.
+log_must zfs snapshot $sendfs@snap
+
+# Create redact_clone and overwrite ONLY the last block (block 15).
+# This is the block at index dn_maxblkid for a 16-block file.
+log_must zfs clone $sendfs@snap $redact_clone
+typeset redact_mnt=$(get_prop mountpoint $redact_clone)
+log_must dd if=/dev/urandom of=$redact_mnt/f1 bs=$bs count=1 seek=15 conv=notrunc
+log_must zfs snapshot $redact_clone@snap
+
+# Create the redaction bookmark; block 15 is now in the redaction list.
+log_must zfs redact $sendfs@snap book1 $redact_clone@snap
+
+# Create send_clone as an unmodified clone of the base snapshot.
+# Block 15 in send_clone is inherited (birth <= snap.creation_txg), so the
+# TO traversal thread does not include it. The PREVIOUSLY_REDACTED path
+# must send it.
+log_must zfs clone $sendfs@snap $send_clone
+log_must zfs snapshot $send_clone@snap
+
+# Redacted send of the base snapshot; block 15 of f1 is omitted.
+log_must eval "zfs send --redact book1 $sendfs@snap >$stream"
+log_must eval "zfs recv $recvfs <$stream"
+
+# Incremental send of send_clone from the redaction bookmark.
+# Block 15 must be sent via the PREVIOUSLY_REDACTED path.
+log_must eval "zfs send -i $sendfs#book1 $send_clone@snap >$stream"
+log_must eval "zfs recv $recv_clone <$stream"
+
+# Verify that the received clone is identical to the source.
+# If the bug is present, block 15 is zeros on the receiver and this fails.
+typeset send_mnt=$(get_prop mountpoint $send_clone)
+typeset recv_mnt=$(get_prop mountpoint $recv_clone)
+log_must directory_diff $send_mnt $recv_mnt
+
+# Explicitly verify block 15 is not all zeros and matches the source.
+typeset src_block=$(mktemp $tmpdir/src_block.XXXX)
+typeset recv_block=$(mktemp $tmpdir/recv_block.XXXX)
+typeset zero_block=$(mktemp $tmpdir/zero_block.XXXX)
+log_must dd if=$mntpnt/f1 bs=$bs skip=15 count=1 of=$src_block 2>/dev/null
+log_must dd if=$recv_mnt/f1 bs=$bs skip=15 count=1 of=$recv_block 2>/dev/null
+log_must dd if=/dev/zero bs=$bs count=1 of=$zero_block 2>/dev/null
+
+cmp -s $recv_block $zero_block && log_fail "Block 15 is all zeros on receiver (off-by-one bug)"
+log_must cmp $src_block $recv_block
+
+log_pass "Incremental send from bookmark correctly sends the last block (dn_maxblkid)."
diff --git a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
index 91430c0e8fc0..2b5a28b06206 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
@@ -419,12 +419,7 @@ function recover_bad_missing_devs
# expected state after a healing resilver of a healthy pool.
#
# 2. sequential - The pool is fully intact. There should never be a
-# checksum error, but the occasional checksum error does occur in
-# practice. Until the root cause is identified and resolved, tolerate
-# a checksum error when scrubbing after a sequential resilver.
-#
-# https://github.com/openzfs/zfs/issues/18307
-# https://github.com/openzfs/zfs/issues/18319
+# checksum error.
#
# 3. damaged - The pool was intentionally silently damaged. Checksum
# errors are expected to be reported as the damaged blocks are
@@ -454,7 +449,7 @@ function verify_draid_pool
log_fail "Unexpected repair IO found for $pool ($cksum)"
fi
elif [[ "$replace_mode" = "sequential" ]]; then
- if [[ $cksum -gt 3 ]]; then
+ if [[ $cksum -gt 0 ]]; then
log_must zpool status -v $pool
log_fail "Unexpected CKSUM errors found for $pool ($cksum)"
fi
diff --git a/sys/modules/zfs/zfs_config.h b/sys/modules/zfs/zfs_config.h
index 77c310c268f8..b4e4c1e4d29b 100644
--- a/sys/modules/zfs/zfs_config.h
+++ b/sys/modules/zfs/zfs_config.h
@@ -204,6 +204,9 @@
/* DECLARE_EVENT_CLASS() is available */
/* #undef HAVE_DECLARE_EVENT_CLASS */
+/* dentry aliases are in d_u member */
+/* #undef HAVE_DENTRY_D_U_ALIASES */
+
/* 3-arg dequeue_signal() takes a type argument */
/* #undef HAVE_DEQUEUE_SIGNAL_3ARG_TYPE */
@@ -911,7 +914,7 @@
/* #undef ZFS_DEVICE_MINOR */
/* Define the project alias string. */
-#define ZFS_META_ALIAS "zfs-2.4.99-551-FreeBSD_g84ffe564d"
+#define ZFS_META_ALIAS "zfs-2.4.99-566-FreeBSD_ga12c6ed62"
/* Define the project author. */
#define ZFS_META_AUTHOR "OpenZFS"
@@ -941,7 +944,7 @@
#define ZFS_META_NAME "zfs"
/* Define the project release. */
-#define ZFS_META_RELEASE "551-FreeBSD_g84ffe564d"
+#define ZFS_META_RELEASE "566-FreeBSD_ga12c6ed62"
/* Define the project version. */
#define ZFS_META_VERSION "2.4.99"
diff --git a/sys/modules/zfs/zfs_gitrev.h b/sys/modules/zfs/zfs_gitrev.h
index af9caaa07622..113c3d7a5bbb 100644
--- a/sys/modules/zfs/zfs_gitrev.h
+++ b/sys/modules/zfs/zfs_gitrev.h
@@ -1 +1 @@
-#define ZFS_META_GITREV "zfs-2.4.99-551-g84ffe564d-dirty"
+#define ZFS_META_GITREV "zfs-2.4.99-566-ga12c6ed62-dirty"