From: Jan Rękorajski Date: Thu, 7 Sep 2023 12:33:52 +0000 (+0200) Subject: - up to 2.2.0-rc3 X-Git-Tag: auto/th/zfs-2.2.0-0.rc3.1 X-Git-Url: http://git.pld-linux.org/?p=packages%2Fzfs.git;a=commitdiff_plain;h=757b8d9475f8bdc5710df221acbd0c6dfcc9fca7 - up to 2.2.0-rc3 --- diff --git a/am.patch b/am.patch deleted file mode 100644 index ca31132..0000000 --- a/am.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index 55cae89fa..8ce1af3b8 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -9,14 +9,14 @@ if CONFIG_USER - endif - endif - if CONFIG_KERNEL --SUBDIRS += module -+SUBDIRS += scripts module - - extradir = $(prefix)/src/zfs-$(VERSION) --extra_HEADERS = zfs.release.in zfs_config.h.in -+extra_HEADERS = zfs.release zfs_config.h - - if BUILD_LINUX - kerneldir = $(prefix)/src/zfs-$(VERSION)/$(LINUX_VERSION) --nodist_kernel_HEADERS = zfs.release zfs_config.h module/$(LINUX_SYMBOLS) -+nodist_kernel_HEADERS = zfs.release.in zfs_config.h.in module/$(LINUX_SYMBOLS) - endif - endif - -@@ -54,8 +54,8 @@ install-data-hook: - cd $(DESTDIR)$(prefix)/src/spl-$(VERSION) && \ - ln -s ../zfs-$(VERSION)/include/spl include && \ - ln -s ../zfs-$(VERSION)/$(LINUX_VERSION) $(LINUX_VERSION) && \ -- ln -s ../zfs-$(VERSION)/zfs_config.h.in spl_config.h.in && \ -- ln -s ../zfs-$(VERSION)/zfs.release.in spl.release.in && \ -+ ln -s ../zfs-$(VERSION)/zfs_config.h spl_config.h && \ -+ ln -s ../zfs-$(VERSION)/zfs.release spl.release && \ - cd $(DESTDIR)$(prefix)/src/zfs-$(VERSION)/$(LINUX_VERSION) && \ - ln -fs zfs_config.h spl_config.h && \ - ln -fs zfs.release spl.release diff --git a/kernel-6.5.patch b/kernel-6.5.patch new file mode 100644 index 0000000..6c4a55f --- /dev/null +++ b/kernel-6.5.patch @@ -0,0 +1,934 @@ +From 3b8e318b7737fa40daf6abbc06ba31cd6ae8d572 Mon Sep 17 00:00:00 2001 +From: Coleman Kane +Date: Tue, 1 Aug 2023 11:32:38 -0400 +Subject: [PATCH] Linux 6.5 compat: use disk_check_media_change when it exists + +When disk_check_media_change() exists, then define +zfs_check_media_change() to simply call disk_check_media_change() on +the bd_disk member of its argument. Since disk_check_media_change() +is newer than when revalidate_disk was present in bops, we should +be able to safely do this via a macro, instead of recreating a new +implementation of the inline function that forces revalidation. + +Reviewed-by: Brian Behlendorf +Reviewed-by: Brian Atkinson +Signed-off-by: Coleman Kane +Closes #15101 +--- + include/os/linux/kernel/linux/blkdev_compat.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h +index e0f20ba32008..1641dd92a918 100644 +--- a/include/os/linux/kernel/linux/blkdev_compat.h ++++ b/include/os/linux/kernel/linux/blkdev_compat.h +@@ -347,6 +347,7 @@ zfs_check_media_change(struct block_device *bdev) + #define vdev_bdev_reread_part(bdev) zfs_check_media_change(bdev) + #elif defined(HAVE_DISK_CHECK_MEDIA_CHANGE) + #define vdev_bdev_reread_part(bdev) disk_check_media_change(bdev->bd_disk) ++#define zfs_check_media_change(bdev) disk_check_media_change(bdev->bd_disk) + #else + /* + * This is encountered if check_disk_change() and bdev_check_media_change() +From 43e8f6e37fddc31f23301cb70d466687bd205cd9 Mon Sep 17 00:00:00 2001 +From: Coleman Kane +Date: Tue, 1 Aug 2023 11:37:20 -0400 +Subject: [PATCH] Linux 6.5 compat: blkdev changes + +Multiple changes to the blkdev API were introduced in Linux 6.5. This +includes passing (void* holder) to blkdev_put, adding a new +blk_holder_ops* arg to blkdev_get_by_path, adding a new blk_mode_t type +that replaces uses of fmode_t, and removing an argument from the release +handler on block_device_operations that we weren't using. The open +function definition has also changed to take gendisk* and blk_mode_t, so +update it accordingly, too. + +Implement local wrappers for blkdev_get_by_path() and +vdev_blkdev_put() so that the in-line calls are cleaner, and place the +conditionally-compiled implementation details inside of both of these +local wrappers. Both calls are exclusively used within vdev_disk.c, at +this time. + +Add blk_mode_is_open_write() to test FMODE_WRITE / BLK_OPEN_WRITE +The wrapper function is now used for testing using the appropriate +method for the kernel, whether the open mode is writable or not. + +Emphasize fmode_t arg in zvol_release is not used + +Reviewed-by: Brian Behlendorf +Signed-off-by: Coleman Kane +Closes #15099 +--- + config/kernel-blkdev.m4 | 84 ++++++++++++++++++- + config/kernel-block-device-operations.m4 | 35 +++++++- + include/os/linux/kernel/linux/blkdev_compat.h | 6 ++ + module/os/linux/zfs/vdev_disk.c | 65 ++++++++++++-- + module/os/linux/zfs/zfs_vnops_os.c | 2 +- + module/os/linux/zfs/zpl_ctldir.c | 2 +- + module/os/linux/zfs/zvol_os.c | 28 ++++++- + 7 files changed, 203 insertions(+), 19 deletions(-) + +diff --git a/config/kernel-blkdev.m4 b/config/kernel-blkdev.m4 +index 887acee670ba..e04a2bd2c3b6 100644 +--- a/config/kernel-blkdev.m4 ++++ b/config/kernel-blkdev.m4 +@@ -16,12 +16,63 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH], [ + ]) + ]) + ++dnl # ++dnl # 6.5.x API change, ++dnl # blkdev_get_by_path() takes 4 args ++dnl # ++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG], [ ++ ZFS_LINUX_TEST_SRC([blkdev_get_by_path_4arg], [ ++ #include ++ #include ++ ], [ ++ struct block_device *bdev __attribute__ ((unused)) = NULL; ++ const char *path = "path"; ++ fmode_t mode = 0; ++ void *holder = NULL; ++ struct blk_holder_ops h; ++ ++ bdev = blkdev_get_by_path(path, mode, holder, &h); ++ ]) ++]) ++ + AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH], [ +- AC_MSG_CHECKING([whether blkdev_get_by_path() exists]) ++ AC_MSG_CHECKING([whether blkdev_get_by_path() exists and takes 3 args]) + ZFS_LINUX_TEST_RESULT([blkdev_get_by_path], [ + AC_MSG_RESULT(yes) + ], [ +- ZFS_LINUX_TEST_ERROR([blkdev_get_by_path()]) ++ AC_MSG_RESULT(no) ++ AC_MSG_CHECKING([whether blkdev_get_by_path() exists and takes 4 args]) ++ ZFS_LINUX_TEST_RESULT([blkdev_get_by_path_4arg], [ ++ AC_DEFINE(HAVE_BLKDEV_GET_BY_PATH_4ARG, 1, ++ [blkdev_get_by_path() exists and takes 4 args]) ++ AC_MSG_RESULT(yes) ++ ], [ ++ ZFS_LINUX_TEST_ERROR([blkdev_get_by_path()]) ++ ]) ++ ]) ++]) ++ ++dnl # ++dnl # 6.5.x API change ++dnl # blk_mode_t was added as a type to supercede some places where fmode_t ++dnl # is used ++dnl # ++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_BLK_MODE_T], [ ++ ZFS_LINUX_TEST_SRC([blk_mode_t], [ ++ #include ++ #include ++ ], [ ++ blk_mode_t m __attribute((unused)) = (blk_mode_t)0; ++ ]) ++]) ++ ++AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BLK_MODE_T], [ ++ AC_MSG_CHECKING([whether blk_mode_t is defined]) ++ ZFS_LINUX_TEST_RESULT([blk_mode_t], [ ++ AC_MSG_RESULT(yes) ++ AC_DEFINE(HAVE_BLK_MODE_T, 1, [blk_mode_t is defined]) ++ ], [ ++ AC_MSG_RESULT(no) + ]) + ]) + +@@ -41,12 +92,35 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_PUT], [ + ]) + ]) + ++dnl # ++dnl # 6.5.x API change. ++dnl # blkdev_put() takes (void* holder) as arg 2 ++dnl # ++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_PUT_HOLDER], [ ++ ZFS_LINUX_TEST_SRC([blkdev_put_holder], [ ++ #include ++ #include ++ ], [ ++ struct block_device *bdev = NULL; ++ void *holder = NULL; ++ ++ blkdev_put(bdev, holder); ++ ]) ++]) ++ + AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_PUT], [ + AC_MSG_CHECKING([whether blkdev_put() exists]) + ZFS_LINUX_TEST_RESULT([blkdev_put], [ + AC_MSG_RESULT(yes) + ], [ +- ZFS_LINUX_TEST_ERROR([blkdev_put()]) ++ AC_MSG_CHECKING([whether blkdev_put() accepts void* as arg 2]) ++ ZFS_LINUX_TEST_RESULT([blkdev_put_holder], [ ++ AC_MSG_RESULT(yes) ++ AC_DEFINE(HAVE_BLKDEV_PUT_HOLDER, 1, ++ [blkdev_put() accepts void* as arg 2]) ++ ], [ ++ ZFS_LINUX_TEST_ERROR([blkdev_put()]) ++ ]) + ]) + ]) + +@@ -495,7 +569,9 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BLK_STS_RESV_CONFLICT], [ + + AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [ + ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH ++ ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG + ZFS_AC_KERNEL_SRC_BLKDEV_PUT ++ ZFS_AC_KERNEL_SRC_BLKDEV_PUT_HOLDER + ZFS_AC_KERNEL_SRC_BLKDEV_REREAD_PART + ZFS_AC_KERNEL_SRC_BLKDEV_INVALIDATE_BDEV + ZFS_AC_KERNEL_SRC_BLKDEV_LOOKUP_BDEV +@@ -510,6 +586,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [ + ZFS_AC_KERNEL_SRC_BLKDEV_PART_TO_DEV + ZFS_AC_KERNEL_SRC_BLKDEV_DISK_CHECK_MEDIA_CHANGE + ZFS_AC_KERNEL_SRC_BLKDEV_BLK_STS_RESV_CONFLICT ++ ZFS_AC_KERNEL_SRC_BLKDEV_BLK_MODE_T + ]) + + AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [ +@@ -530,4 +607,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [ + ZFS_AC_KERNEL_BLKDEV_PART_TO_DEV + ZFS_AC_KERNEL_BLKDEV_DISK_CHECK_MEDIA_CHANGE + ZFS_AC_KERNEL_BLKDEV_BLK_STS_RESV_CONFLICT ++ ZFS_AC_KERNEL_BLKDEV_BLK_MODE_T + ]) +diff --git a/config/kernel-block-device-operations.m4 b/config/kernel-block-device-operations.m4 +index 84e39dc8a2f6..d13c1337b1fb 100644 +--- a/config/kernel-block-device-operations.m4 ++++ b/config/kernel-block-device-operations.m4 +@@ -49,12 +49,42 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [ + ], [], []) + ]) + ++dnl # ++dnl # 5.9.x API change ++dnl # ++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG], [ ++ ZFS_LINUX_TEST_SRC([block_device_operations_release_void_1arg], [ ++ #include ++ ++ void blk_release(struct gendisk *g) { ++ (void) g; ++ return; ++ } ++ ++ static const struct block_device_operations ++ bops __attribute__ ((unused)) = { ++ .open = NULL, ++ .release = blk_release, ++ .ioctl = NULL, ++ .compat_ioctl = NULL, ++ }; ++ ], [], []) ++]) ++ + AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [ +- AC_MSG_CHECKING([whether bops->release() is void]) ++ AC_MSG_CHECKING([whether bops->release() is void and takes 2 args]) + ZFS_LINUX_TEST_RESULT([block_device_operations_release_void], [ + AC_MSG_RESULT(yes) + ],[ +- ZFS_LINUX_TEST_ERROR([bops->release()]) ++ AC_MSG_RESULT(no) ++ AC_MSG_CHECKING([whether bops->release() is void and takes 1 arg]) ++ ZFS_LINUX_TEST_RESULT([block_device_operations_release_void_1arg], [ ++ AC_MSG_RESULT(yes) ++ AC_DEFINE([HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG], [1], ++ [Define if release() in block_device_operations takes 1 arg]) ++ ],[ ++ ZFS_LINUX_TEST_ERROR([bops->release()]) ++ ]) + ]) + ]) + +@@ -92,6 +122,7 @@ AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [ + 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 + ]) + +diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h +index 1641dd92a918..f111e648ccf7 100644 +--- a/include/os/linux/kernel/linux/blkdev_compat.h ++++ b/include/os/linux/kernel/linux/blkdev_compat.h +@@ -398,6 +398,12 @@ vdev_lookup_bdev(const char *path, dev_t *dev) + #endif + } + ++#if defined(HAVE_BLK_MODE_T) ++#define blk_mode_is_open_write(flag) ((flag) & BLK_OPEN_WRITE) ++#else ++#define blk_mode_is_open_write(flag) ((flag) & FMODE_WRITE) ++#endif ++ + /* + * Kernels without bio_set_op_attrs use bi_rw for the bio flags. + */ +diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c +index 925ee9d9fe9c..48ac55f07034 100644 +--- a/module/os/linux/zfs/vdev_disk.c ++++ b/module/os/linux/zfs/vdev_disk.c +@@ -80,9 +80,22 @@ typedef struct dio_request { + + static unsigned int zfs_vdev_failfast_mask = 1; + ++#ifdef HAVE_BLK_MODE_T ++static blk_mode_t ++#else + static fmode_t ++#endif + vdev_bdev_mode(spa_mode_t spa_mode) + { ++#ifdef HAVE_BLK_MODE_T ++ blk_mode_t mode = 0; ++ ++ if (spa_mode & SPA_MODE_READ) ++ mode |= BLK_OPEN_READ; ++ ++ if (spa_mode & SPA_MODE_WRITE) ++ mode |= BLK_OPEN_WRITE; ++#else + fmode_t mode = 0; + + if (spa_mode & SPA_MODE_READ) +@@ -90,6 +103,7 @@ vdev_bdev_mode(spa_mode_t spa_mode) + + if (spa_mode & SPA_MODE_WRITE) + mode |= FMODE_WRITE; ++#endif + + return (mode); + } +@@ -197,12 +211,47 @@ vdev_disk_kobj_evt_post(vdev_t *v) + } + } + ++#if !defined(HAVE_BLKDEV_GET_BY_PATH_4ARG) ++/* ++ * Define a dummy struct blk_holder_ops for kernel versions ++ * prior to 6.5. ++ */ ++struct blk_holder_ops {}; ++#endif ++ ++static struct block_device * ++vdev_blkdev_get_by_path(const char *path, spa_mode_t mode, void *holder, ++ const struct blk_holder_ops *hops) ++{ ++#ifdef HAVE_BLKDEV_GET_BY_PATH_4ARG ++ return (blkdev_get_by_path(path, ++ vdev_bdev_mode(mode) | BLK_OPEN_EXCL, holder, hops)); ++#else ++ return (blkdev_get_by_path(path, ++ vdev_bdev_mode(mode) | FMODE_EXCL, holder)); ++#endif ++} ++ ++static void ++vdev_blkdev_put(struct block_device *bdev, spa_mode_t mode, void *holder) ++{ ++#ifdef HAVE_BLKDEV_PUT_HOLDER ++ return (blkdev_put(bdev, holder)); ++#else ++ return (blkdev_put(bdev, vdev_bdev_mode(mode) | FMODE_EXCL)); ++#endif ++} ++ + static int + vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, + uint64_t *logical_ashift, uint64_t *physical_ashift) + { + struct block_device *bdev; ++#ifdef HAVE_BLK_MODE_T ++ blk_mode_t mode = vdev_bdev_mode(spa_mode(v->vdev_spa)); ++#else + fmode_t mode = vdev_bdev_mode(spa_mode(v->vdev_spa)); ++#endif + hrtime_t timeout = MSEC2NSEC(zfs_vdev_open_timeout_ms); + vdev_disk_t *vd; + +@@ -252,15 +301,15 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, + reread_part = B_TRUE; + } + +- blkdev_put(bdev, mode | FMODE_EXCL); ++ vdev_blkdev_put(bdev, mode, zfs_vdev_holder); + } + + if (reread_part) { +- bdev = blkdev_get_by_path(disk_name, mode | FMODE_EXCL, +- zfs_vdev_holder); ++ bdev = vdev_blkdev_get_by_path(disk_name, mode, ++ zfs_vdev_holder, NULL); + if (!IS_ERR(bdev)) { + int error = vdev_bdev_reread_part(bdev); +- blkdev_put(bdev, mode | FMODE_EXCL); ++ vdev_blkdev_put(bdev, mode, zfs_vdev_holder); + if (error == 0) { + timeout = MSEC2NSEC( + zfs_vdev_open_timeout_ms * 2); +@@ -305,8 +354,8 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, + hrtime_t start = gethrtime(); + bdev = ERR_PTR(-ENXIO); + while (IS_ERR(bdev) && ((gethrtime() - start) < timeout)) { +- bdev = blkdev_get_by_path(v->vdev_path, mode | FMODE_EXCL, +- zfs_vdev_holder); ++ bdev = vdev_blkdev_get_by_path(v->vdev_path, mode, ++ zfs_vdev_holder, NULL); + if (unlikely(PTR_ERR(bdev) == -ENOENT)) { + /* + * There is no point of waiting since device is removed +@@ -382,8 +431,8 @@ vdev_disk_close(vdev_t *v) + return; + + if (vd->vd_bdev != NULL) { +- blkdev_put(vd->vd_bdev, +- vdev_bdev_mode(spa_mode(v->vdev_spa)) | FMODE_EXCL); ++ vdev_blkdev_put(vd->vd_bdev, spa_mode(v->vdev_spa), ++ zfs_vdev_holder); + } + + rw_destroy(&vd->vd_lock); +diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c +index 234c4d5ef0e0..33baac9db06b 100644 +--- a/module/os/linux/zfs/zfs_vnops_os.c ++++ b/module/os/linux/zfs/zfs_vnops_os.c +@@ -186,7 +186,7 @@ zfs_open(struct inode *ip, int mode, int flag, cred_t *cr) + return (error); + + /* Honor ZFS_APPENDONLY file attribute */ +- if ((mode & FMODE_WRITE) && (zp->z_pflags & ZFS_APPENDONLY) && ++ if (blk_mode_is_open_write(mode) && (zp->z_pflags & ZFS_APPENDONLY) && + ((flag & O_APPEND) == 0)) { + zfs_exit(zfsvfs, FTAG); + return (SET_ERROR(EPERM)); +diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c +index 68a7de78f471..7786444fea35 100644 +--- a/module/os/linux/zfs/zpl_ctldir.c ++++ b/module/os/linux/zfs/zpl_ctldir.c +@@ -42,7 +42,7 @@ + static int + zpl_common_open(struct inode *ip, struct file *filp) + { +- if (filp->f_mode & FMODE_WRITE) ++ if (blk_mode_is_open_write(filp->f_mode)) + return (-EACCES); + + return (generic_file_open(ip, filp)); +diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c +index 38bc8e2c4eeb..7a95b54bdf0d 100644 +--- a/module/os/linux/zfs/zvol_os.c ++++ b/module/os/linux/zfs/zvol_os.c +@@ -671,7 +671,11 @@ zvol_request(struct request_queue *q, struct bio *bio) + } + + static int ++#ifdef HAVE_BLK_MODE_T ++zvol_open(struct gendisk *disk, blk_mode_t flag) ++#else + zvol_open(struct block_device *bdev, fmode_t flag) ++#endif + { + zvol_state_t *zv; + int error = 0; +@@ -686,10 +690,14 @@ zvol_open(struct block_device *bdev, fmode_t flag) + /* + * Obtain a copy of private_data under the zvol_state_lock to make + * sure that either the result of zvol free code path setting +- * bdev->bd_disk->private_data to NULL is observed, or zvol_os_free() ++ * disk->private_data to NULL is observed, or zvol_os_free() + * is not called on this zv because of the positive zv_open_count. + */ ++#ifdef HAVE_BLK_MODE_T ++ zv = disk->private_data; ++#else + zv = bdev->bd_disk->private_data; ++#endif + if (zv == NULL) { + rw_exit(&zvol_state_lock); + return (SET_ERROR(-ENXIO)); +@@ -769,14 +777,15 @@ zvol_open(struct block_device *bdev, fmode_t flag) + } + } + +- error = -zvol_first_open(zv, !(flag & FMODE_WRITE)); ++ error = -zvol_first_open(zv, !(blk_mode_is_open_write(flag))); + + if (drop_namespace) + mutex_exit(&spa_namespace_lock); + } + + if (error == 0) { +- if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) { ++ if ((blk_mode_is_open_write(flag)) && ++ (zv->zv_flags & ZVOL_RDONLY)) { + if (zv->zv_open_count == 0) + zvol_last_close(zv); + +@@ -791,14 +800,25 @@ zvol_open(struct block_device *bdev, fmode_t flag) + rw_exit(&zv->zv_suspend_lock); + + if (error == 0) ++#ifdef HAVE_BLK_MODE_T ++ disk_check_media_change(disk); ++#else + zfs_check_media_change(bdev); ++#endif + + return (error); + } + + static void +-zvol_release(struct gendisk *disk, fmode_t mode) ++#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG ++zvol_release(struct gendisk *disk) ++#else ++zvol_release(struct gendisk *disk, fmode_t unused) ++#endif + { ++#if !defined(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG) ++ (void) unused; ++#endif + zvol_state_t *zv; + boolean_t drop_suspend = B_TRUE; + +From e47e9bbe86f2e8fe5da0fc7c3a9014e1f8c132a9 Mon Sep 17 00:00:00 2001 +From: Coleman Kane +Date: Wed, 2 Aug 2023 17:05:46 -0400 +Subject: [PATCH] Linux 6.5 compat: register_sysctl_table removed + +Additionally, the .child element of ctl_table has been removed in 6.5. +This change adds a new test for the pre-6.5 register_sysctl_table() +function, and uses the old code in that case. If it isn't found, then +the parentage entries in the tables are removed, and the register_sysctl +call is provided the paths of "kernel/spl", "kernel/spl/kmem", and +"kernel/spl/kstat" directly, to populate each subdirectory over three +calls, as is the new API. + +Reviewed-by: Brian Atkinson +Reviewed-by: Brian Behlendorf +Signed-off-by: Coleman Kane +Closes #15138 +--- + config/kernel-register_sysctl_table.m4 | 27 ++++++++++++++++++++++++++ + config/kernel.m4 | 2 ++ + module/os/linux/spl/spl-proc.c | 26 ++++++++++++++++++++++--- + 3 files changed, 52 insertions(+), 3 deletions(-) + create mode 100644 config/kernel-register_sysctl_table.m4 + +diff --git a/config/kernel-register_sysctl_table.m4 b/config/kernel-register_sysctl_table.m4 +new file mode 100644 +index 000000000000..a5e934f56d29 +--- /dev/null ++++ b/config/kernel-register_sysctl_table.m4 +@@ -0,0 +1,27 @@ ++dnl # ++dnl # Linux 6.5 removes register_sysctl_table ++dnl # ++AC_DEFUN([ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE], [ ++ ZFS_LINUX_TEST_SRC([has_register_sysctl_table], [ ++ #include ++ ++ static struct ctl_table dummy_table[] = { ++ {} ++ }; ++ ++ ],[ ++ struct ctl_table_header *h ++ __attribute((unused)) = register_sysctl_table(dummy_table); ++ ]) ++]) ++ ++AC_DEFUN([ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE], [ ++ AC_MSG_CHECKING([whether register_sysctl_table exists]) ++ ZFS_LINUX_TEST_RESULT([has_register_sysctl_table], [ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE(HAVE_REGISTER_SYSCTL_TABLE, 1, ++ [register_sysctl_table exists]) ++ ],[ ++ AC_MSG_RESULT([no]) ++ ]) ++]) +diff --git a/config/kernel.m4 b/config/kernel.m4 +index 1487fa2e7793..28bd361d33ff 100644 +--- a/config/kernel.m4 ++++ b/config/kernel.m4 +@@ -160,6 +160,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ + ZFS_AC_KERNEL_SRC_FILEMAP + ZFS_AC_KERNEL_SRC_WRITEPAGE_T + ZFS_AC_KERNEL_SRC_RECLAIMED ++ ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE + case "$host_cpu" in + powerpc*) + ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE +@@ -299,6 +300,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ + ZFS_AC_KERNEL_FILEMAP + ZFS_AC_KERNEL_WRITEPAGE_T + ZFS_AC_KERNEL_RECLAIMED ++ ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE + case "$host_cpu" in + powerpc*) + ZFS_AC_KERNEL_CPU_HAS_FEATURE +diff --git a/module/os/linux/spl/spl-proc.c b/module/os/linux/spl/spl-proc.c +index 01f5619e1893..bcc356ae55b6 100644 +--- a/module/os/linux/spl/spl-proc.c ++++ b/module/os/linux/spl/spl-proc.c +@@ -624,6 +624,7 @@ static struct ctl_table spl_table[] = { + .mode = 0644, + .proc_handler = &proc_dohostid, + }, ++#ifdef HAVE_REGISTER_SYSCTL_TABLE + { + .procname = "kmem", + .mode = 0555, +@@ -634,9 +635,11 @@ static struct ctl_table spl_table[] = { + .mode = 0555, + .child = spl_kstat_table, + }, ++#endif + {}, + }; + ++#ifdef HAVE_REGISTER_SYSCTL_TABLE + static struct ctl_table spl_dir[] = { + { + .procname = "spl", +@@ -648,21 +651,38 @@ static struct ctl_table spl_dir[] = { + + static struct ctl_table spl_root[] = { + { +- .procname = "kernel", +- .mode = 0555, +- .child = spl_dir, ++ .procname = "kernel", ++ .mode = 0555, ++ .child = spl_dir, + }, + {} + }; ++#endif + + int + spl_proc_init(void) + { + int rc = 0; + ++#ifdef HAVE_REGISTER_SYSCTL_TABLE + spl_header = register_sysctl_table(spl_root); + if (spl_header == NULL) + return (-EUNATCH); ++#else ++ spl_header = register_sysctl("kernel/spl", spl_table); ++ if (spl_header == NULL) ++ return (-EUNATCH); ++ ++ if (register_sysctl("kernel/spl/kmem", spl_kmem_table) == NULL) { ++ rc = -EUNATCH; ++ goto out; ++ } ++ ++ if (register_sysctl("kernel/spl/kstat", spl_kstat_table) == NULL) { ++ rc = -EUNATCH; ++ goto out; ++ } ++#endif + + proc_spl = proc_mkdir("spl", NULL); + if (proc_spl == NULL) { +From 36261c8238df462b214854ccea1df4f060cf0995 Mon Sep 17 00:00:00 2001 +From: Coleman Kane +Date: Mon, 7 Aug 2023 18:47:46 -0400 +Subject: [PATCH] Linux 6.5 compat: replace generic_file_splice_read with + filemap_splice_read + +The generic_file_splice_read function was removed in Linux 6.5 in favor +of filemap_splice_read. Add an autoconf test for filemap_splice_read and +use it if it is found as the handler for .splice_read in the +file_operations struct. Additionally, ITER_PIPE was removed in 6.5. This +change removes the ITER_* macros that OpenZFS doesn't use from being +tested in config/kernel-vfs-iov_iter.m4. The removal of ITER_PIPE was +causing the test to fail, which also affected the code responsible for +setting the .splice_read handler, above. That behavior caused run-time +panics on Linux 6.5. + +Reviewed-by: Brian Atkinson +Reviewed-by: Brian Behlendorf +Signed-off-by: Coleman Kane +Closes #15155 +--- + config/kernel-filemap-splice-read.m4 | 25 +++++++++++++++++++++++++ + config/kernel-vfs-iov_iter.m4 | 3 +-- + config/kernel.m4 | 2 ++ + module/os/linux/zfs/zpl_file.c | 4 ++++ + 4 files changed, 32 insertions(+), 2 deletions(-) + create mode 100644 config/kernel-filemap-splice-read.m4 + +diff --git a/config/kernel-filemap-splice-read.m4 b/config/kernel-filemap-splice-read.m4 +new file mode 100644 +index 000000000000..5199b7373e4d +--- /dev/null ++++ b/config/kernel-filemap-splice-read.m4 +@@ -0,0 +1,25 @@ ++AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ], [ ++ dnl # ++ dnl # Kernel 6.5 - generic_file_splice_read was removed in favor ++ dnl # of filemap_splice_read for the .splice_read member of the ++ dnl # file_operations struct. ++ dnl # ++ ZFS_LINUX_TEST_SRC([has_filemap_splice_read], [ ++ #include ++ ++ struct file_operations fops __attribute__((unused)) = { ++ .splice_read = filemap_splice_read, ++ }; ++ ],[]) ++]) ++ ++AC_DEFUN([ZFS_AC_KERNEL_FILEMAP_SPLICE_READ], [ ++ AC_MSG_CHECKING([whether filemap_splice_read() exists]) ++ ZFS_LINUX_TEST_RESULT([has_filemap_splice_read], [ ++ AC_MSG_RESULT(yes) ++ AC_DEFINE(HAVE_FILEMAP_SPLICE_READ, 1, ++ [filemap_splice_read exists]) ++ ],[ ++ AC_MSG_RESULT(no) ++ ]) ++]) +diff --git a/config/kernel-vfs-iov_iter.m4 b/config/kernel-vfs-iov_iter.m4 +index cc5a7ab0c237..ff560ff3eef0 100644 +--- a/config/kernel-vfs-iov_iter.m4 ++++ b/config/kernel-vfs-iov_iter.m4 +@@ -6,8 +6,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_IOV_ITER], [ + #include + #include + ],[ +- int type __attribute__ ((unused)) = +- ITER_IOVEC | ITER_KVEC | ITER_BVEC | ITER_PIPE; ++ int type __attribute__ ((unused)) = ITER_KVEC; + ]) + + ZFS_LINUX_TEST_SRC([iov_iter_advance], [ +diff --git a/config/kernel.m4 b/config/kernel.m4 +index 28bd361d33ff..309f1819be48 100644 +--- a/config/kernel.m4 ++++ b/config/kernel.m4 +@@ -161,6 +161,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ + ZFS_AC_KERNEL_SRC_WRITEPAGE_T + ZFS_AC_KERNEL_SRC_RECLAIMED + ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE ++ ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ + case "$host_cpu" in + powerpc*) + ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE +@@ -301,6 +302,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ + ZFS_AC_KERNEL_WRITEPAGE_T + ZFS_AC_KERNEL_RECLAIMED + ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE ++ ZFS_AC_KERNEL_FILEMAP_SPLICE_READ + case "$host_cpu" in + powerpc*) + ZFS_AC_KERNEL_CPU_HAS_FEATURE +diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c +index f6af2ebd1163..24cc1064a8fc 100644 +--- a/module/os/linux/zfs/zpl_file.c ++++ b/module/os/linux/zfs/zpl_file.c +@@ -1323,7 +1323,11 @@ const struct file_operations zpl_file_operations = { + .read_iter = zpl_iter_read, + .write_iter = zpl_iter_write, + #ifdef HAVE_VFS_IOV_ITER ++#ifdef HAVE_FILEMAP_SPLICE_READ ++ .splice_read = filemap_splice_read, ++#else + .splice_read = generic_file_splice_read, ++#endif + .splice_write = iter_file_splice_write, + #endif + #else +From 8ce2eba9e6a384feef93d77c397f37d17dc588ce Mon Sep 17 00:00:00 2001 +From: Coleman Kane +Date: Tue, 8 Aug 2023 18:42:32 -0400 +Subject: [PATCH] Linux 6.5 compat: Use copy_splice_read instead of + filemap_splice_read + +Using the filemap_splice_read function for the splice_read handler was +leading to occasional data corruption under certain circumstances. Favor +using copy_splice_read instead, which does not demonstrate the same +erroneous behavior under the tested failure cases. + +Reviewed-by: Brian Atkinson +Reviewed-by: Brian Behlendorf +Signed-off-by: Coleman Kane +Closes #15164 +--- + config/kernel-filemap-splice-read.m4 | 18 +++++++++--------- + config/kernel.m4 | 4 ++-- + module/os/linux/zfs/zpl_file.c | 4 ++-- + 3 files changed, 13 insertions(+), 13 deletions(-) + +diff --git a/config/kernel-filemap-splice-read.m4 b/config/kernel-filemap-splice-read.m4 +index 5199b7373e4d..4c83b31d738a 100644 +--- a/config/kernel-filemap-splice-read.m4 ++++ b/config/kernel-filemap-splice-read.m4 +@@ -1,24 +1,24 @@ +-AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ], [ ++AC_DEFUN([ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ], [ + dnl # + dnl # Kernel 6.5 - generic_file_splice_read was removed in favor +- dnl # of filemap_splice_read for the .splice_read member of the ++ dnl # of copy_splice_read for the .splice_read member of the + dnl # file_operations struct. + dnl # +- ZFS_LINUX_TEST_SRC([has_filemap_splice_read], [ ++ ZFS_LINUX_TEST_SRC([has_copy_splice_read], [ + #include + + struct file_operations fops __attribute__((unused)) = { +- .splice_read = filemap_splice_read, ++ .splice_read = copy_splice_read, + }; + ],[]) + ]) + +-AC_DEFUN([ZFS_AC_KERNEL_FILEMAP_SPLICE_READ], [ +- AC_MSG_CHECKING([whether filemap_splice_read() exists]) +- ZFS_LINUX_TEST_RESULT([has_filemap_splice_read], [ ++AC_DEFUN([ZFS_AC_KERNEL_COPY_SPLICE_READ], [ ++ AC_MSG_CHECKING([whether copy_splice_read() exists]) ++ ZFS_LINUX_TEST_RESULT([has_copy_splice_read], [ + AC_MSG_RESULT(yes) +- AC_DEFINE(HAVE_FILEMAP_SPLICE_READ, 1, +- [filemap_splice_read exists]) ++ AC_DEFINE(HAVE_COPY_SPLICE_READ, 1, ++ [copy_splice_read exists]) + ],[ + AC_MSG_RESULT(no) + ]) +diff --git a/config/kernel.m4 b/config/kernel.m4 +index 309f1819be48..df194ec72207 100644 +--- a/config/kernel.m4 ++++ b/config/kernel.m4 +@@ -161,7 +161,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ + ZFS_AC_KERNEL_SRC_WRITEPAGE_T + ZFS_AC_KERNEL_SRC_RECLAIMED + ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE +- ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ ++ ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ + case "$host_cpu" in + powerpc*) + ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE +@@ -302,7 +302,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ + ZFS_AC_KERNEL_WRITEPAGE_T + ZFS_AC_KERNEL_RECLAIMED + ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE +- ZFS_AC_KERNEL_FILEMAP_SPLICE_READ ++ ZFS_AC_KERNEL_COPY_SPLICE_READ + case "$host_cpu" in + powerpc*) + ZFS_AC_KERNEL_CPU_HAS_FEATURE +diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c +index 24cc1064a8fc..3caa0fc6c214 100644 +--- a/module/os/linux/zfs/zpl_file.c ++++ b/module/os/linux/zfs/zpl_file.c +@@ -1323,8 +1323,8 @@ const struct file_operations zpl_file_operations = { + .read_iter = zpl_iter_read, + .write_iter = zpl_iter_write, + #ifdef HAVE_VFS_IOV_ITER +-#ifdef HAVE_FILEMAP_SPLICE_READ +- .splice_read = filemap_splice_read, ++#ifdef HAVE_COPY_SPLICE_READ ++ .splice_read = copy_splice_read, + #else + .splice_read = generic_file_splice_read, + #endif +From bcb1159c095f57564914b59f5e7e82170261afb0 Mon Sep 17 00:00:00 2001 +From: Andrea Righi +Date: Sat, 2 Sep 2023 02:21:40 +0200 +Subject: [PATCH] Linux 6.5 compat: safe cleanup in spl_proc_fini() + +If we fail to create a proc entry in spl_proc_init() we may end up +calling unregister_sysctl_table() twice: one in the failure path of +spl_proc_init() and another time during spl_proc_fini(). + +Avoid the double call to unregister_sysctl_table() and while at it +refactor the code a bit to reduce code duplication. + +This was accidentally introduced when the spl code was +updated for Linux 6.5 compatibility. + +Reviewed-by: Brian Behlendorf +Reviewed-by: Ameer Hamza +Signed-off-by: Andrea Righi +Closes #15234 +Closes #15235 +--- + module/os/linux/spl/spl-proc.c | 36 +++++++++++++++++----------------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/module/os/linux/spl/spl-proc.c b/module/os/linux/spl/spl-proc.c +index bcc356ae55b6..5cb5a6dadb05 100644 +--- a/module/os/linux/spl/spl-proc.c ++++ b/module/os/linux/spl/spl-proc.c +@@ -659,6 +659,21 @@ static struct ctl_table spl_root[] = { + }; + #endif + ++static void spl_proc_cleanup(void) ++{ ++ remove_proc_entry("kstat", proc_spl); ++ remove_proc_entry("slab", proc_spl_kmem); ++ remove_proc_entry("kmem", proc_spl); ++ remove_proc_entry("taskq-all", proc_spl); ++ remove_proc_entry("taskq", proc_spl); ++ remove_proc_entry("spl", NULL); ++ ++ if (spl_header) { ++ unregister_sysctl_table(spl_header); ++ spl_header = NULL; ++ } ++} ++ + int + spl_proc_init(void) + { +@@ -723,15 +738,8 @@ spl_proc_init(void) + goto out; + } + out: +- if (rc) { +- remove_proc_entry("kstat", proc_spl); +- remove_proc_entry("slab", proc_spl_kmem); +- remove_proc_entry("kmem", proc_spl); +- remove_proc_entry("taskq-all", proc_spl); +- remove_proc_entry("taskq", proc_spl); +- remove_proc_entry("spl", NULL); +- unregister_sysctl_table(spl_header); +- } ++ if (rc) ++ spl_proc_cleanup(); + + return (rc); + } +@@ -739,13 +747,5 @@ spl_proc_init(void) + void + spl_proc_fini(void) + { +- remove_proc_entry("kstat", proc_spl); +- remove_proc_entry("slab", proc_spl_kmem); +- remove_proc_entry("kmem", proc_spl); +- remove_proc_entry("taskq-all", proc_spl); +- remove_proc_entry("taskq", proc_spl); +- remove_proc_entry("spl", NULL); +- +- ASSERT(spl_header != NULL); +- unregister_sysctl_table(spl_header); ++ spl_proc_cleanup(); + } diff --git a/no-Werror.patch b/no-Werror.patch deleted file mode 100644 index 1d0f326..0000000 --- a/no-Werror.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- zfs-2.1.5/config/kernel.m4~ 2022-06-22 18:55:53.000000000 +0200 -+++ zfs-2.1.5/config/kernel.m4 2022-09-24 08:10:59.050219049 +0200 -@@ -581,7 +581,7 @@ - # Example command line to manually build source - # make modules -C $LINUX_OBJ $ARCH_UM M=$PWD/build/$1 - --ccflags-y := -Werror $FRAME_LARGER_THAN -+ccflags-y := $FRAME_LARGER_THAN - _ACEOF - - dnl # Additional custom CFLAGS as requested. diff --git a/staging.patch b/staging.patch deleted file mode 100644 index c6131ed..0000000 --- a/staging.patch +++ /dev/null @@ -1,5955 +0,0 @@ -diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c -index f424dd771..bcd520de3 100644 ---- a/cmd/zdb/zdb.c -+++ b/cmd/zdb/zdb.c -@@ -3102,13 +3102,22 @@ dump_znode_sa_xattr(sa_handle_t *hdl) - (void) printf("\tSA xattrs: %d bytes, %d entries\n\n", - sa_xattr_size, sa_xattr_entries); - while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL) { -+ boolean_t can_print = !dump_opt['P']; - uchar_t *value; - uint_t cnt, idx; - - (void) printf("\t\t%s = ", nvpair_name(elem)); - nvpair_value_byte_array(elem, &value, &cnt); -+ -+ for (idx = 0; idx < cnt; ++idx) { -+ if (!isprint(value[idx])) { -+ can_print = B_FALSE; -+ break; -+ } -+ } -+ - for (idx = 0; idx < cnt; ++idx) { -- if (isprint(value[idx])) -+ if (can_print) - (void) putchar(value[idx]); - else - (void) printf("\\%3.3o", value[idx]); -diff --git a/cmd/zed/agents/zfs_retire.c b/cmd/zed/agents/zfs_retire.c -index b4794e311..29eaee750 100644 ---- a/cmd/zed/agents/zfs_retire.c -+++ b/cmd/zed/agents/zfs_retire.c -@@ -444,14 +444,16 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, - return; - - /* Remove the vdev since device is unplugged */ -+ int remove_status = 0; - if (l2arc || (strcmp(class, "resource.fs.zfs.removed") == 0)) { -- int status = zpool_vdev_remove_wanted(zhp, devname); -+ remove_status = zpool_vdev_remove_wanted(zhp, devname); - fmd_hdl_debug(hdl, "zpool_vdev_remove_wanted '%s'" -- ", ret:%d", devname, status); -+ ", err:%d", devname, libzfs_errno(zhdl)); - } - - /* Replace the vdev with a spare if its not a l2arc */ -- if (!l2arc && (!fmd_prop_get_int32(hdl, "spare_on_remove") || -+ if (!l2arc && !remove_status && -+ (!fmd_prop_get_int32(hdl, "spare_on_remove") || - replace_with_spare(hdl, zhp, vdev) == B_FALSE)) { - /* Could not handle with spare */ - fmd_hdl_debug(hdl, "no spare for '%s'", devname); -diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c -index 2311d4f04..a06af9aec 100644 ---- a/cmd/zpool/zpool_main.c -+++ b/cmd/zpool/zpool_main.c -@@ -392,7 +392,7 @@ get_usage(zpool_help_t idx) - case HELP_REOPEN: - return (gettext("\treopen [-n] \n")); - case HELP_INITIALIZE: -- return (gettext("\tinitialize [-c | -s] [-w] " -+ return (gettext("\tinitialize [-c | -s | -u] [-w] " - "[ ...]\n")); - case HELP_SCRUB: - return (gettext("\tscrub [-s | -p] [-w] ...\n")); -@@ -548,12 +548,13 @@ usage(boolean_t requested) - } - - /* -- * zpool initialize [-c | -s] [-w] [ ...] -+ * zpool initialize [-c | -s | -u] [-w] [ ...] - * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool - * if none specified. - * - * -c Cancel. Ends active initializing. - * -s Suspend. Initializing can then be restarted with no flags. -+ * -u Uninitialize. Clears initialization state. - * -w Wait. Blocks until initializing has completed. - */ - int -@@ -569,12 +570,14 @@ zpool_do_initialize(int argc, char **argv) - struct option long_options[] = { - {"cancel", no_argument, NULL, 'c'}, - {"suspend", no_argument, NULL, 's'}, -+ {"uninit", no_argument, NULL, 'u'}, - {"wait", no_argument, NULL, 'w'}, - {0, 0, 0, 0} - }; - - pool_initialize_func_t cmd_type = POOL_INITIALIZE_START; -- while ((c = getopt_long(argc, argv, "csw", long_options, NULL)) != -1) { -+ while ((c = getopt_long(argc, argv, "csuw", long_options, -+ NULL)) != -1) { - switch (c) { - case 'c': - if (cmd_type != POOL_INITIALIZE_START && -@@ -594,6 +597,15 @@ zpool_do_initialize(int argc, char **argv) - } - cmd_type = POOL_INITIALIZE_SUSPEND; - break; -+ case 'u': -+ if (cmd_type != POOL_INITIALIZE_START && -+ cmd_type != POOL_INITIALIZE_UNINIT) { -+ (void) fprintf(stderr, gettext("-u cannot be " -+ "combined with other options\n")); -+ usage(B_FALSE); -+ } -+ cmd_type = POOL_INITIALIZE_UNINIT; -+ break; - case 'w': - wait = B_TRUE; - break; -@@ -620,8 +632,8 @@ zpool_do_initialize(int argc, char **argv) - } - - if (wait && (cmd_type != POOL_INITIALIZE_START)) { -- (void) fprintf(stderr, gettext("-w cannot be used with -c or " -- "-s\n")); -+ (void) fprintf(stderr, gettext("-w cannot be used with -c, -s" -+ "or -u\n")); - usage(B_FALSE); - } - -@@ -6921,6 +6933,17 @@ zpool_do_online(int argc, char **argv) - return (1); - - for (i = 1; i < argc; i++) { -+ vdev_state_t oldstate; -+ boolean_t avail_spare, l2cache; -+ nvlist_t *tgt = zpool_find_vdev(zhp, argv[i], &avail_spare, -+ &l2cache, NULL); -+ if (tgt == NULL) { -+ ret = 1; -+ continue; -+ } -+ uint_t vsc; -+ oldstate = ((vdev_stat_t *)fnvlist_lookup_uint64_array(tgt, -+ ZPOOL_CONFIG_VDEV_STATS, &vsc))->vs_state; - if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) { - if (newstate != VDEV_STATE_HEALTHY) { - (void) printf(gettext("warning: device '%s' " -@@ -6934,6 +6957,17 @@ zpool_do_online(int argc, char **argv) - (void) printf(gettext("use 'zpool " - "replace' to replace devices " - "that are no longer present\n")); -+ if ((flags & ZFS_ONLINE_EXPAND)) { -+ (void) printf(gettext("%s: failed " -+ "to expand usable space on " -+ "unhealthy device '%s'\n"), -+ (oldstate >= VDEV_STATE_DEGRADED ? -+ "error" : "warning"), argv[i]); -+ if (oldstate >= VDEV_STATE_DEGRADED) { -+ ret = 1; -+ break; -+ } -+ } - } - } else { - ret = 1; -@@ -7549,19 +7583,20 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps) - - zfs_nicebytes(ps->pss_processed, processed_buf, sizeof (processed_buf)); - -- assert(ps->pss_func == POOL_SCAN_SCRUB || -- ps->pss_func == POOL_SCAN_RESILVER); -+ int is_resilver = ps->pss_func == POOL_SCAN_RESILVER; -+ int is_scrub = ps->pss_func == POOL_SCAN_SCRUB; -+ assert(is_resilver || is_scrub); - - /* Scan is finished or canceled. */ - if (ps->pss_state == DSS_FINISHED) { - secs_to_dhms(end - start, time_buf); - -- if (ps->pss_func == POOL_SCAN_SCRUB) { -+ if (is_scrub) { - (void) printf(gettext("scrub repaired %s " - "in %s with %llu errors on %s"), processed_buf, - time_buf, (u_longlong_t)ps->pss_errors, - ctime(&end)); -- } else if (ps->pss_func == POOL_SCAN_RESILVER) { -+ } else if (is_resilver) { - (void) printf(gettext("resilvered %s " - "in %s with %llu errors on %s"), processed_buf, - time_buf, (u_longlong_t)ps->pss_errors, -@@ -7569,10 +7604,10 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps) - } - return; - } else if (ps->pss_state == DSS_CANCELED) { -- if (ps->pss_func == POOL_SCAN_SCRUB) { -+ if (is_scrub) { - (void) printf(gettext("scrub canceled on %s"), - ctime(&end)); -- } else if (ps->pss_func == POOL_SCAN_RESILVER) { -+ } else if (is_resilver) { - (void) printf(gettext("resilver canceled on %s"), - ctime(&end)); - } -@@ -7582,7 +7617,7 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps) - assert(ps->pss_state == DSS_SCANNING); - - /* Scan is in progress. Resilvers can't be paused. */ -- if (ps->pss_func == POOL_SCAN_SCRUB) { -+ if (is_scrub) { - if (pause == 0) { - (void) printf(gettext("scrub in progress since %s"), - ctime(&start)); -@@ -7592,7 +7627,7 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps) - (void) printf(gettext("\tscrub started on %s"), - ctime(&start)); - } -- } else if (ps->pss_func == POOL_SCAN_RESILVER) { -+ } else if (is_resilver) { - (void) printf(gettext("resilver in progress since %s"), - ctime(&start)); - } -@@ -7634,17 +7669,27 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps) - scanned_buf, issued_buf, total_buf); - } - -- if (ps->pss_func == POOL_SCAN_RESILVER) { -+ if (is_resilver) { - (void) printf(gettext("\t%s resilvered, %.2f%% done"), - processed_buf, 100 * fraction_done); -- } else if (ps->pss_func == POOL_SCAN_SCRUB) { -+ } else if (is_scrub) { - (void) printf(gettext("\t%s repaired, %.2f%% done"), - processed_buf, 100 * fraction_done); - } - - if (pause == 0) { -+ /* -+ * Only provide an estimate iff: -+ * 1) the time remaining is valid, and -+ * 2) the issue rate exceeds 10 MB/s, and -+ * 3) it's either: -+ * a) a resilver which has started repairs, or -+ * b) a scrub which has entered the issue phase. -+ */ - if (total_secs_left != UINT64_MAX && -- issue_rate >= 10 * 1024 * 1024) { -+ issue_rate >= 10 * 1024 * 1024 && -+ ((is_resilver && ps->pss_processed > 0) || -+ (is_scrub && issued > 0))) { - (void) printf(gettext(", %s to go\n"), time_buf); - } else { - (void) printf(gettext(", no estimated " -diff --git a/config/always-compiler-options.m4 b/config/always-compiler-options.m4 -index 5046ce0dd..0f66db584 100644 ---- a/config/always-compiler-options.m4 -+++ b/config/always-compiler-options.m4 -@@ -221,3 +221,34 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_IPA_SRA], [ - CFLAGS="$saved_flags" - AC_SUBST([NO_IPA_SRA]) - ]) -+ -+dnl # -+dnl # Check if kernel cc supports -fno-ipa-sra option. -+dnl # -+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_KERNEL_CC_NO_IPA_SRA], [ -+ AC_MSG_CHECKING([whether $KERNEL_CC supports -fno-ipa-sra]) -+ -+ saved_cc="$CC" -+ saved_flags="$CFLAGS" -+ CC="gcc" -+ CFLAGS="$CFLAGS -Werror -fno-ipa-sra" -+ -+ AS_IF([ test -n "$KERNEL_CC" ], [ -+ CC="$KERNEL_CC" -+ ]) -+ AS_IF([ test -n "$KERNEL_LLVM" ], [ -+ CC="clang" -+ ]) -+ -+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], [ -+ KERNEL_NO_IPA_SRA=-fno-ipa-sra -+ AC_MSG_RESULT([yes]) -+ ], [ -+ KERNEL_NO_IPA_SRA= -+ AC_MSG_RESULT([no]) -+ ]) -+ -+ CC="$saved_cc" -+ CFLAGS="$saved_flags" -+ AC_SUBST([KERNEL_NO_IPA_SRA]) -+]) -diff --git a/config/kernel-acl.m4 b/config/kernel-acl.m4 -index 6e92da97d..be08c3c60 100644 ---- a/config/kernel-acl.m4 -+++ b/config/kernel-acl.m4 -@@ -236,7 +236,22 @@ dnl # - dnl # 6.2 API change, - dnl # set_acl() second paramter changed to a struct dentry * - dnl # -+dnl # 6.3 API change, -+dnl # set_acl() first parameter changed to struct mnt_idmap * -+dnl # - AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OPERATIONS_SET_ACL], [ -+ ZFS_LINUX_TEST_SRC([inode_operations_set_acl_mnt_idmap_dentry], [ -+ #include -+ -+ int set_acl_fn(struct mnt_idmap *idmap, -+ struct dentry *dent, struct posix_acl *acl, -+ int type) { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .set_acl = set_acl_fn, -+ }; -+ ],[]) - ZFS_LINUX_TEST_SRC([inode_operations_set_acl_userns_dentry], [ - #include - -@@ -281,17 +296,24 @@ AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL], [ - AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists]) - AC_DEFINE(HAVE_SET_ACL_USERNS, 1, [iops->set_acl() takes 4 args]) - ],[ -- ZFS_LINUX_TEST_RESULT([inode_operations_set_acl_userns_dentry], [ -+ ZFS_LINUX_TEST_RESULT([inode_operations_set_acl_mnt_idmap_dentry], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists]) -- AC_DEFINE(HAVE_SET_ACL_USERNS_DENTRY_ARG2, 1, -- [iops->set_acl() takes 4 args, arg2 is struct dentry *]) -+ AC_DEFINE(HAVE_SET_ACL_IDMAP_DENTRY, 1, -+ [iops->set_acl() takes 4 args, arg1 is struct mnt_idmap *]) - ],[ -- ZFS_LINUX_TEST_RESULT([inode_operations_set_acl], [ -+ ZFS_LINUX_TEST_RESULT([inode_operations_set_acl_userns_dentry], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists, takes 3 args]) -+ AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists]) -+ AC_DEFINE(HAVE_SET_ACL_USERNS_DENTRY_ARG2, 1, -+ [iops->set_acl() takes 4 args, arg2 is struct dentry *]) - ],[ -- ZFS_LINUX_REQUIRE_API([i_op->set_acl()], [3.14]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_set_acl], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists, takes 3 args]) -+ ],[ -+ ZFS_LINUX_REQUIRE_API([i_op->set_acl()], [3.14]) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-cpu_has_feature.m4 b/config/kernel-cpu_has_feature.m4 -new file mode 100644 -index 000000000..608faf0f8 ---- /dev/null -+++ b/config/kernel-cpu_has_feature.m4 -@@ -0,0 +1,29 @@ -+dnl # -+dnl # cpu_has_feature() may referencing GPL-only cpu_feature_keys on powerpc -+dnl # -+ -+dnl # -+dnl # Checking if cpu_has_feature is exported GPL-only -+dnl # -+AC_DEFUN([ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE], [ -+ ZFS_LINUX_TEST_SRC([cpu_has_feature], [ -+ #include -+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) -+ #include -+ #else -+ #include -+ #endif -+ ], [ -+ return cpu_has_feature(CPU_FTR_ALTIVEC) ? 0 : 1; -+ ], [], [ZFS_META_LICENSE]) -+]) -+AC_DEFUN([ZFS_AC_KERNEL_CPU_HAS_FEATURE], [ -+ AC_MSG_CHECKING([whether cpu_has_feature() is GPL-only]) -+ ZFS_LINUX_TEST_RESULT([cpu_has_feature_license], [ -+ AC_MSG_RESULT(no) -+ ], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_CPU_HAS_FEATURE_GPL_ONLY, 1, -+ [cpu_has_feature() is GPL-only]) -+ ]) -+]) -diff --git a/config/kernel-filemap.m4 b/config/kernel-filemap.m4 -new file mode 100644 -index 000000000..745928168 ---- /dev/null -+++ b/config/kernel-filemap.m4 -@@ -0,0 +1,26 @@ -+dnl # -+dnl # filemap_range_has_page was not available till 4.13 -+dnl # -+AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP], [ -+ ZFS_LINUX_TEST_SRC([filemap_range_has_page], [ -+ #include -+ ],[ -+ struct address_space *mapping = NULL; -+ loff_t lstart = 0; -+ loff_t lend = 0; -+ bool ret __attribute__ ((unused)); -+ -+ ret = filemap_range_has_page(mapping, lstart, lend); -+ ]) -+]) -+ -+AC_DEFUN([ZFS_AC_KERNEL_FILEMAP], [ -+ AC_MSG_CHECKING([whether filemap_range_has_page() is available]) -+ ZFS_LINUX_TEST_RESULT([filemap_range_has_page], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_FILEMAP_RANGE_HAS_PAGE, 1, -+ [filemap_range_has_page() is available]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) -+]) -diff --git a/config/kernel-flush_dcache_page.m4 b/config/kernel-flush_dcache_page.m4 -new file mode 100644 -index 000000000..2340c386e ---- /dev/null -+++ b/config/kernel-flush_dcache_page.m4 -@@ -0,0 +1,26 @@ -+dnl # -+dnl # Starting from Linux 5.13, flush_dcache_page() becomes an inline -+dnl # function and may indirectly referencing GPL-only cpu_feature_keys on -+dnl # powerpc -+dnl # -+ -+dnl # -+dnl # Checking if flush_dcache_page is exported GPL-only -+dnl # -+AC_DEFUN([ZFS_AC_KERNEL_SRC_FLUSH_DCACHE_PAGE], [ -+ ZFS_LINUX_TEST_SRC([flush_dcache_page], [ -+ #include -+ ], [ -+ flush_dcache_page(0); -+ ], [], [ZFS_META_LICENSE]) -+]) -+AC_DEFUN([ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE], [ -+ AC_MSG_CHECKING([whether flush_dcache_page() is GPL-only]) -+ ZFS_LINUX_TEST_RESULT([flush_dcache_page_license], [ -+ AC_MSG_RESULT(no) -+ ], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY, 1, -+ [flush_dcache_page() is GPL-only]) -+ ]) -+]) -diff --git a/config/kernel-generic_fillattr.m4 b/config/kernel-generic_fillattr.m4 -index 0acd5d531..02dee4d4c 100644 ---- a/config/kernel-generic_fillattr.m4 -+++ b/config/kernel-generic_fillattr.m4 -@@ -4,7 +4,10 @@ dnl # - dnl # generic_fillattr in linux/fs.h now requires a struct user_namespace* - dnl # as the first arg, to support idmapped mounts. - dnl # --AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS], [ -+dnl # 6.3 API -+dnl # generic_fillattr() now takes struct mnt_idmap* as the first argument -+dnl # -+AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR], [ - ZFS_LINUX_TEST_SRC([generic_fillattr_userns], [ - #include - ],[ -@@ -13,16 +16,32 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS], [ - struct kstat *k = NULL; - generic_fillattr(userns, in, k); - ]) -+ -+ ZFS_LINUX_TEST_SRC([generic_fillattr_mnt_idmap], [ -+ #include -+ ],[ -+ struct mnt_idmap *idmap = NULL; -+ struct inode *in = NULL; -+ struct kstat *k = NULL; -+ generic_fillattr(idmap, in, k); -+ ]) - ]) - --AC_DEFUN([ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS], [ -- AC_MSG_CHECKING([whether generic_fillattr requires struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT([generic_fillattr_userns], [ -+AC_DEFUN([ZFS_AC_KERNEL_GENERIC_FILLATTR], [ -+ AC_MSG_CHECKING([whether generic_fillattr requires struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT([generic_fillattr_mnt_idmap], [ - AC_MSG_RESULT([yes]) -- AC_DEFINE(HAVE_GENERIC_FILLATTR_USERNS, 1, -- [generic_fillattr requires struct user_namespace*]) -+ AC_DEFINE(HAVE_GENERIC_FILLATTR_IDMAP, 1, -+ [generic_fillattr requires struct mnt_idmap*]) - ],[ -- AC_MSG_RESULT([no]) -+ AC_MSG_CHECKING([whether generic_fillattr requires struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT([generic_fillattr_userns], [ -+ AC_MSG_RESULT([yes]) -+ AC_DEFINE(HAVE_GENERIC_FILLATTR_USERNS, 1, -+ [generic_fillattr requires struct user_namespace*]) -+ ],[ -+ AC_MSG_RESULT([no]) -+ ]) - ]) - ]) - -diff --git a/config/kernel-inode-create.m4 b/config/kernel-inode-create.m4 -index a6ea11fb6..9e9e43180 100644 ---- a/config/kernel-inode-create.m4 -+++ b/config/kernel-inode-create.m4 -@@ -1,4 +1,22 @@ - AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE], [ -+ dnl # -+ dnl # 6.3 API change -+ dnl # The first arg is changed to struct mnt_idmap * -+ dnl # -+ ZFS_LINUX_TEST_SRC([create_mnt_idmap], [ -+ #include -+ #include -+ -+ int inode_create(struct mnt_idmap *idmap, -+ struct inode *inode ,struct dentry *dentry, -+ umode_t umode, bool flag) { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .create = inode_create, -+ }; -+ ],[]) -+ - dnl # - dnl # 5.12 API change that added the struct user_namespace* arg - dnl # to the front of this function type's arg list. -@@ -35,19 +53,28 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE], [ - ]) - - AC_DEFUN([ZFS_AC_KERNEL_CREATE], [ -- AC_MSG_CHECKING([whether iops->create() takes struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT([create_userns], [ -+ AC_MSG_CHECKING([whether iops->create() takes struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT([create_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_IOPS_CREATE_USERNS, 1, -- [iops->create() takes struct user_namespace*]) -+ AC_DEFINE(HAVE_IOPS_CREATE_IDMAP, 1, -+ [iops->create() takes struct mnt_idmap*]) - ],[ - AC_MSG_RESULT(no) - -- AC_MSG_CHECKING([whether iops->create() passes flags]) -- ZFS_LINUX_TEST_RESULT([create_flags], [ -+ AC_MSG_CHECKING([whether iops->create() takes struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT([create_userns], [ - AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_IOPS_CREATE_USERNS, 1, -+ [iops->create() takes struct user_namespace*]) - ],[ -- ZFS_LINUX_TEST_ERROR([iops->create()]) -+ AC_MSG_RESULT(no) -+ -+ AC_MSG_CHECKING([whether iops->create() passes flags]) -+ ZFS_LINUX_TEST_RESULT([create_flags], [ -+ AC_MSG_RESULT(yes) -+ ],[ -+ ZFS_LINUX_TEST_ERROR([iops->create()]) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-inode-getattr.m4 b/config/kernel-inode-getattr.m4 -index f62e82f52..c8bfb0786 100644 ---- a/config/kernel-inode-getattr.m4 -+++ b/config/kernel-inode-getattr.m4 -@@ -1,4 +1,24 @@ - AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GETATTR], [ -+ dnl # -+ dnl # Linux 6.3 API -+ dnl # The first arg of getattr I/O operations handler type -+ dnl # is changed to struct mnt_idmap* -+ dnl # -+ ZFS_LINUX_TEST_SRC([inode_operations_getattr_mnt_idmap], [ -+ #include -+ -+ int test_getattr( -+ struct mnt_idmap *idmap, -+ const struct path *p, struct kstat *k, -+ u32 request_mask, unsigned int query_flags) -+ { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .getattr = test_getattr, -+ }; -+ ],[]) -+ - dnl # - dnl # Linux 5.12 API - dnl # The getattr I/O operations handler type was extended to require -@@ -55,37 +75,48 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GETATTR], [ - - AC_DEFUN([ZFS_AC_KERNEL_INODE_GETATTR], [ - dnl # -- dnl # Kernel 5.12 test -+ dnl # Kernel 6.3 test - dnl # -- AC_MSG_CHECKING([whether iops->getattr() takes user_namespace]) -- ZFS_LINUX_TEST_RESULT([inode_operations_getattr_userns], [ -+ AC_MSG_CHECKING([whether iops->getattr() takes mnt_idmap]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_getattr_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_USERNS_IOPS_GETATTR, 1, -- [iops->getattr() takes struct user_namespace*]) -+ AC_DEFINE(HAVE_IDMAP_IOPS_GETATTR, 1, -+ [iops->getattr() takes struct mnt_idmap*]) - ],[ - AC_MSG_RESULT(no) -- - dnl # -- dnl # Kernel 4.11 test -+ dnl # Kernel 5.12 test - dnl # -- AC_MSG_CHECKING([whether iops->getattr() takes a path]) -- ZFS_LINUX_TEST_RESULT([inode_operations_getattr_path], [ -+ AC_MSG_CHECKING([whether iops->getattr() takes user_namespace]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_getattr_userns], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1, -- [iops->getattr() takes a path]) -+ AC_DEFINE(HAVE_USERNS_IOPS_GETATTR, 1, -+ [iops->getattr() takes struct user_namespace*]) - ],[ - AC_MSG_RESULT(no) - - dnl # -- dnl # Kernel < 4.11 test -+ dnl # Kernel 4.11 test - dnl # -- AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount]) -- ZFS_LINUX_TEST_RESULT([inode_operations_getattr_vfsmount], [ -+ AC_MSG_CHECKING([whether iops->getattr() takes a path]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_getattr_path], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1, -- [iops->getattr() takes a vfsmount]) -+ AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1, -+ [iops->getattr() takes a path]) - ],[ - AC_MSG_RESULT(no) -+ -+ dnl # -+ dnl # Kernel < 4.11 test -+ dnl # -+ AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_getattr_vfsmount], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1, -+ [iops->getattr() takes a vfsmount]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-inode-setattr.m4 b/config/kernel-inode-setattr.m4 -new file mode 100644 -index 000000000..45755b4eb ---- /dev/null -+++ b/config/kernel-inode-setattr.m4 -@@ -0,0 +1,87 @@ -+AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_SETATTR], [ -+ dnl # -+ dnl # Linux 6.3 API -+ dnl # The first arg of setattr I/O operations handler type -+ dnl # is changed to struct mnt_idmap* -+ dnl # -+ ZFS_LINUX_TEST_SRC([inode_operations_setattr_mnt_idmap], [ -+ #include -+ -+ int test_setattr( -+ struct mnt_idmap *idmap, -+ struct dentry *de, struct iattr *ia) -+ { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .setattr = test_setattr, -+ }; -+ ],[]) -+ -+ dnl # -+ dnl # Linux 5.12 API -+ dnl # The setattr I/O operations handler type was extended to require -+ dnl # a struct user_namespace* as its first arg, to support idmapped -+ dnl # mounts. -+ dnl # -+ ZFS_LINUX_TEST_SRC([inode_operations_setattr_userns], [ -+ #include -+ -+ int test_setattr( -+ struct user_namespace *userns, -+ struct dentry *de, struct iattr *ia) -+ { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .setattr = test_setattr, -+ }; -+ ],[]) -+ -+ ZFS_LINUX_TEST_SRC([inode_operations_setattr], [ -+ #include -+ -+ int test_setattr( -+ struct dentry *de, struct iattr *ia) -+ { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .setattr = test_setattr, -+ }; -+ ],[]) -+]) -+ -+AC_DEFUN([ZFS_AC_KERNEL_INODE_SETATTR], [ -+ dnl # -+ dnl # Kernel 6.3 test -+ dnl # -+ AC_MSG_CHECKING([whether iops->setattr() takes mnt_idmap]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_setattr_mnt_idmap], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_IDMAP_IOPS_SETATTR, 1, -+ [iops->setattr() takes struct mnt_idmap*]) -+ ],[ -+ AC_MSG_RESULT(no) -+ dnl # -+ dnl # Kernel 5.12 test -+ dnl # -+ AC_MSG_CHECKING([whether iops->setattr() takes user_namespace]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_setattr_userns], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_USERNS_IOPS_SETATTR, 1, -+ [iops->setattr() takes struct user_namespace*]) -+ ],[ -+ AC_MSG_RESULT(no) -+ -+ AC_MSG_CHECKING([whether iops->setattr() exists]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_setattr], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_IOPS_SETATTR, 1, -+ [iops->setattr() exists]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) -+ ]) -+ ]) -+]) -diff --git a/config/kernel-is_owner_or_cap.m4 b/config/kernel-is_owner_or_cap.m4 -index a90cf3da6..4e9c002b7 100644 ---- a/config/kernel-is_owner_or_cap.m4 -+++ b/config/kernel-is_owner_or_cap.m4 -@@ -16,12 +16,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OWNER_OR_CAPABLE], [ - (void) inode_owner_or_capable(ip); - ]) - -- ZFS_LINUX_TEST_SRC([inode_owner_or_capable_idmapped], [ -+ ZFS_LINUX_TEST_SRC([inode_owner_or_capable_userns], [ - #include - ],[ - struct inode *ip = NULL; - (void) inode_owner_or_capable(&init_user_ns, ip); - ]) -+ -+ ZFS_LINUX_TEST_SRC([inode_owner_or_capable_mnt_idmap], [ -+ #include -+ #include -+ ],[ -+ struct inode *ip = NULL; -+ (void) inode_owner_or_capable(&nop_mnt_idmap, ip); -+ ]) - ]) - - AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [ -@@ -35,12 +43,21 @@ AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [ - - AC_MSG_CHECKING( - [whether inode_owner_or_capable() takes user_ns]) -- ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_idmapped], [ -+ ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_userns], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_IDMAPPED, 1, -+ AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_USERNS, 1, - [inode_owner_or_capable() takes user_ns]) - ],[ -- ZFS_LINUX_TEST_ERROR([capability]) -+ AC_MSG_RESULT(no) -+ AC_MSG_CHECKING( -+ [whether inode_owner_or_capable() takes mnt_idmap]) -+ ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_mnt_idmap], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_IDMAP, 1, -+ [inode_owner_or_capable() takes mnt_idmap]) -+ ], [ -+ ZFS_LINUX_TEST_ERROR([capability]) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4 -index 6667ed04f..7407a791b 100644 ---- a/config/kernel-mkdir.m4 -+++ b/config/kernel-mkdir.m4 -@@ -2,6 +2,22 @@ dnl # - dnl # Supported mkdir() interfaces checked newest to oldest. - dnl # - AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [ -+ dnl # -+ dnl # 6.3 API change -+ dnl # mkdir() takes struct mnt_idmap * as the first arg -+ dnl # -+ ZFS_LINUX_TEST_SRC([mkdir_mnt_idmap], [ -+ #include -+ -+ int mkdir(struct mnt_idmap *idmap, -+ struct inode *inode, struct dentry *dentry, -+ umode_t umode) { return 0; } -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .mkdir = mkdir, -+ }; -+ ],[]) -+ - dnl # - dnl # 5.12 API change - dnl # The struct user_namespace arg was added as the first argument to -@@ -43,25 +59,36 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [ - - AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [ - dnl # -- dnl # 5.12 API change -- dnl # The struct user_namespace arg was added as the first argument to -- dnl # mkdir() of the iops structure. -+ dnl # 6.3 API change -+ dnl # mkdir() takes struct mnt_idmap * as the first arg - dnl # -- AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [ -+ AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1, -- [iops->mkdir() takes struct user_namespace*]) -+ AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1, -+ [iops->mkdir() takes struct mnt_idmap*]) - ],[ -- AC_MSG_RESULT(no) -- -- AC_MSG_CHECKING([whether iops->mkdir() takes umode_t]) -- ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [ -+ dnl # -+ dnl # 5.12 API change -+ dnl # The struct user_namespace arg was added as the first argument to -+ dnl # mkdir() of the iops structure. -+ dnl # -+ AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_MKDIR_UMODE_T, 1, -- [iops->mkdir() takes umode_t]) -+ AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1, -+ [iops->mkdir() takes struct user_namespace*]) - ],[ -- ZFS_LINUX_TEST_ERROR([mkdir()]) -+ AC_MSG_RESULT(no) -+ -+ AC_MSG_CHECKING([whether iops->mkdir() takes umode_t]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_MKDIR_UMODE_T, 1, -+ [iops->mkdir() takes umode_t]) -+ ],[ -+ ZFS_LINUX_TEST_ERROR([mkdir()]) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-mknod.m4 b/config/kernel-mknod.m4 -index ffe451060..1494ec1ae 100644 ---- a/config/kernel-mknod.m4 -+++ b/config/kernel-mknod.m4 -@@ -1,4 +1,22 @@ - AC_DEFUN([ZFS_AC_KERNEL_SRC_MKNOD], [ -+ dnl # -+ dnl # 6.3 API change -+ dnl # The first arg is now struct mnt_idmap* -+ dnl # -+ ZFS_LINUX_TEST_SRC([mknod_mnt_idmap], [ -+ #include -+ #include -+ -+ int tmp_mknod(struct mnt_idmap *idmap, -+ struct inode *inode ,struct dentry *dentry, -+ umode_t u, dev_t d) { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .mknod = tmp_mknod, -+ }; -+ ],[]) -+ - dnl # - dnl # 5.12 API change that added the struct user_namespace* arg - dnl # to the front of this function type's arg list. -@@ -19,12 +37,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKNOD], [ - ]) - - AC_DEFUN([ZFS_AC_KERNEL_MKNOD], [ -- AC_MSG_CHECKING([whether iops->mknod() takes struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT([mknod_userns], [ -+ AC_MSG_CHECKING([whether iops->mknod() takes struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT([mknod_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_IOPS_MKNOD_USERNS, 1, -- [iops->mknod() takes struct user_namespace*]) -+ AC_DEFINE(HAVE_IOPS_MKNOD_IDMAP, 1, -+ [iops->mknod() takes struct mnt_idmap*]) - ],[ - AC_MSG_RESULT(no) -+ AC_MSG_CHECKING([whether iops->mknod() takes struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT([mknod_userns], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_IOPS_MKNOD_USERNS, 1, -+ [iops->mknod() takes struct user_namespace*]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) - ]) - ]) -diff --git a/config/kernel-reclaim_state.m4 b/config/kernel-reclaim_state.m4 -new file mode 100644 -index 000000000..9936b3c10 ---- /dev/null -+++ b/config/kernel-reclaim_state.m4 -@@ -0,0 +1,26 @@ -+AC_DEFUN([ZFS_AC_KERNEL_SRC_RECLAIMED], [ -+ dnl # -+ dnl # 6.4 API change -+ dnl # The reclaimed_slab of struct reclaim_state -+ dnl # is renamed to reclaimed -+ dnl # -+ ZFS_LINUX_TEST_SRC([reclaim_state_reclaimed], [ -+ #include -+ static const struct reclaim_state -+ rs __attribute__ ((unused)) = { -+ .reclaimed = 100, -+ }; -+ ],[]) -+]) -+ -+AC_DEFUN([ZFS_AC_KERNEL_RECLAIMED], [ -+ AC_MSG_CHECKING([whether struct reclaim_state has reclaimed field]) -+ ZFS_LINUX_TEST_RESULT([reclaim_state_reclaimed], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_RECLAIM_STATE_RECLAIMED, 1, -+ [struct reclaim_state has reclaimed]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) -+]) -+ -diff --git a/config/kernel-rename.m4 b/config/kernel-rename.m4 -index 302db43f5..b33cd0bfb 100644 ---- a/config/kernel-rename.m4 -+++ b/config/kernel-rename.m4 -@@ -33,24 +33,48 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME], [ - .rename = rename_fn, - }; - ],[]) -+ -+ dnl # -+ dnl # 6.3 API change - the first arg is now struct mnt_idmap* -+ dnl # -+ ZFS_LINUX_TEST_SRC([inode_operations_rename_mnt_idmap], [ -+ #include -+ int rename_fn(struct mnt_idmap *idmap, struct inode *sip, -+ struct dentry *sdp, struct inode *tip, struct dentry *tdp, -+ unsigned int flags) { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .rename = rename_fn, -+ }; -+ ],[]) - ]) - - AC_DEFUN([ZFS_AC_KERNEL_RENAME], [ -- AC_MSG_CHECKING([whether iops->rename() takes struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT([inode_operations_rename_userns], [ -+ AC_MSG_CHECKING([whether iops->rename() takes struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_rename_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_IOPS_RENAME_USERNS, 1, -- [iops->rename() takes struct user_namespace*]) -+ AC_DEFINE(HAVE_IOPS_RENAME_IDMAP, 1, -+ [iops->rename() takes struct mnt_idmap*]) - ],[ - AC_MSG_RESULT(no) - -- AC_MSG_CHECKING([whether iop->rename() wants flags]) -- ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [ -+ AC_MSG_CHECKING([whether iops->rename() takes struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_rename_userns], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, -- [iops->rename() wants flags]) -+ AC_DEFINE(HAVE_IOPS_RENAME_USERNS, 1, -+ [iops->rename() takes struct user_namespace*]) - ],[ - AC_MSG_RESULT(no) -+ -+ AC_MSG_CHECKING([whether iops->rename() wants flags]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, -+ [iops->rename() wants flags]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-setattr-prepare.m4 b/config/kernel-setattr-prepare.m4 -index 24245aa53..e02d6263e 100644 ---- a/config/kernel-setattr-prepare.m4 -+++ b/config/kernel-setattr-prepare.m4 -@@ -27,26 +27,48 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SETATTR_PREPARE], [ - int error __attribute__ ((unused)) = - setattr_prepare(userns, dentry, attr); - ]) -+ -+ dnl # -+ dnl # 6.3 API change -+ dnl # The first arg of setattr_prepare() is changed to struct mnt_idmap* -+ dnl # -+ ZFS_LINUX_TEST_SRC([setattr_prepare_mnt_idmap], [ -+ #include -+ ], [ -+ struct dentry *dentry = NULL; -+ struct iattr *attr = NULL; -+ struct mnt_idmap *idmap = NULL; -+ int error __attribute__ ((unused)) = -+ setattr_prepare(idmap, dentry, attr); -+ ]) - ]) - - AC_DEFUN([ZFS_AC_KERNEL_SETATTR_PREPARE], [ -- AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns], -+ AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_mnt_idmap], - [setattr_prepare], [fs/attr.c], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1, -- [setattr_prepare() accepts user_namespace]) -+ AC_DEFINE(HAVE_SETATTR_PREPARE_IDMAP, 1, -+ [setattr_prepare() accepts mnt_idmap]) - ], [ -- AC_MSG_RESULT(no) -- -- AC_MSG_CHECKING([whether setattr_prepare() is available, doesn't accept user_namespace]) -- ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare], -- [setattr_prepare], [fs/attr.c], [ -+ AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns], -+ [setattr_prepare], [fs/attr.c], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_SETATTR_PREPARE_NO_USERNS, 1, -- [setattr_prepare() is available, doesn't accept user_namespace]) -+ AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1, -+ [setattr_prepare() accepts user_namespace]) - ], [ - AC_MSG_RESULT(no) -+ -+ AC_MSG_CHECKING([whether setattr_prepare() is available, doesn't accept user_namespace]) -+ ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare], -+ [setattr_prepare], [fs/attr.c], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_SETATTR_PREPARE_NO_USERNS, 1, -+ [setattr_prepare() is available, doesn't accept user_namespace]) -+ ], [ -+ AC_MSG_RESULT(no) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-symlink.m4 b/config/kernel-symlink.m4 -index d90366d04..a0333ed66 100644 ---- a/config/kernel-symlink.m4 -+++ b/config/kernel-symlink.m4 -@@ -1,4 +1,20 @@ - AC_DEFUN([ZFS_AC_KERNEL_SRC_SYMLINK], [ -+ dnl # -+ dnl # 6.3 API change that changed the first arg -+ dnl # to struct mnt_idmap* -+ dnl # -+ ZFS_LINUX_TEST_SRC([symlink_mnt_idmap], [ -+ #include -+ #include -+ int tmp_symlink(struct mnt_idmap *idmap, -+ struct inode *inode ,struct dentry *dentry, -+ const char *path) { return 0; } -+ -+ static const struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .symlink = tmp_symlink, -+ }; -+ ],[]) - dnl # - dnl # 5.12 API change that added the struct user_namespace* arg - dnl # to the front of this function type's arg list. -@@ -19,12 +35,19 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SYMLINK], [ - ]) - - AC_DEFUN([ZFS_AC_KERNEL_SYMLINK], [ -- AC_MSG_CHECKING([whether iops->symlink() takes struct user_namespace*]) -- ZFS_LINUX_TEST_RESULT([symlink_userns], [ -+ AC_MSG_CHECKING([whether iops->symlink() takes struct mnt_idmap*]) -+ ZFS_LINUX_TEST_RESULT([symlink_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_IOPS_SYMLINK_USERNS, 1, -- [iops->symlink() takes struct user_namespace*]) -+ AC_DEFINE(HAVE_IOPS_SYMLINK_IDMAP, 1, -+ [iops->symlink() takes struct mnt_idmap*]) - ],[ -- AC_MSG_RESULT(no) -+ AC_MSG_CHECKING([whether iops->symlink() takes struct user_namespace*]) -+ ZFS_LINUX_TEST_RESULT([symlink_userns], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_IOPS_SYMLINK_USERNS, 1, -+ [iops->symlink() takes struct user_namespace*]) -+ ],[ -+ AC_MSG_RESULT(no) -+ ]) - ]) - ]) -diff --git a/config/kernel-tmpfile.m4 b/config/kernel-tmpfile.m4 -index 0e1deb361..cc18b8f65 100644 ---- a/config/kernel-tmpfile.m4 -+++ b/config/kernel-tmpfile.m4 -@@ -4,6 +4,19 @@ dnl # Add support for i_op->tmpfile - dnl # - AC_DEFUN([ZFS_AC_KERNEL_SRC_TMPFILE], [ - dnl # -+ dnl # 6.3 API change -+ dnl # The first arg is now struct mnt_idmap * -+ dnl # -+ ZFS_LINUX_TEST_SRC([inode_operations_tmpfile_mnt_idmap], [ -+ #include -+ int tmpfile(struct mnt_idmap *idmap, -+ struct inode *inode, struct file *file, -+ umode_t mode) { return 0; } -+ static struct inode_operations -+ iops __attribute__ ((unused)) = { -+ .tmpfile = tmpfile, -+ }; -+ ],[]) - dnl # 6.1 API change - dnl # use struct file instead of struct dentry - dnl # -@@ -44,23 +57,29 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_TMPFILE], [ - - AC_DEFUN([ZFS_AC_KERNEL_TMPFILE], [ - AC_MSG_CHECKING([whether i_op->tmpfile() exists]) -- ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile], [ -+ ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_mnt_idmap], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists]) -- AC_DEFINE(HAVE_TMPFILE_USERNS, 1, [i_op->tmpfile() has userns]) -- ],[ -- ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry_userns], [ -+ AC_DEFINE(HAVE_TMPFILE_IDMAP, 1, [i_op->tmpfile() has mnt_idmap]) -+ ], [ -+ ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists]) - AC_DEFINE(HAVE_TMPFILE_USERNS, 1, [i_op->tmpfile() has userns]) -- AC_DEFINE(HAVE_TMPFILE_DENTRY, 1, [i_op->tmpfile() uses old dentry signature]) - ],[ -- ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry], [ -+ ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry_userns], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists]) -+ AC_DEFINE(HAVE_TMPFILE_USERNS, 1, [i_op->tmpfile() has userns]) - AC_DEFINE(HAVE_TMPFILE_DENTRY, 1, [i_op->tmpfile() uses old dentry signature]) - ],[ -- ZFS_LINUX_REQUIRE_API([i_op->tmpfile()], [3.11]) -+ ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists]) -+ AC_DEFINE(HAVE_TMPFILE_DENTRY, 1, [i_op->tmpfile() uses old dentry signature]) -+ ],[ -+ ZFS_LINUX_REQUIRE_API([i_op->tmpfile()], [3.11]) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel-writepage_t.m4 b/config/kernel-writepage_t.m4 -new file mode 100644 -index 000000000..3a0cffd98 ---- /dev/null -+++ b/config/kernel-writepage_t.m4 -@@ -0,0 +1,26 @@ -+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 -+ 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/config/kernel-xattr-handler.m4 b/config/kernel-xattr-handler.m4 -index b6cbfa155..6b8a08dbc 100644 ---- a/config/kernel-xattr-handler.m4 -+++ b/config/kernel-xattr-handler.m4 -@@ -179,6 +179,21 @@ dnl # - dnl # Supported xattr handler set() interfaces checked newest to oldest. - dnl # - AC_DEFUN([ZFS_AC_KERNEL_SRC_XATTR_HANDLER_SET], [ -+ ZFS_LINUX_TEST_SRC([xattr_handler_set_mnt_idmap], [ -+ #include -+ -+ int set(const struct xattr_handler *handler, -+ struct mnt_idmap *idmap, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, const void *buffer, -+ size_t size, int flags) -+ { return 0; } -+ static const struct xattr_handler -+ xops __attribute__ ((unused)) = { -+ .set = set, -+ }; -+ ],[]) -+ - ZFS_LINUX_TEST_SRC([xattr_handler_set_userns], [ - #include - -@@ -240,53 +255,63 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [ - dnl # The xattr_handler->set() callback was changed to 8 arguments, and - dnl # struct user_namespace* was inserted as arg #2 - dnl # -- AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and user_namespace]) -- ZFS_LINUX_TEST_RESULT([xattr_handler_set_userns], [ -+ dnl # 6.3 API change, -+ dnl # The xattr_handler->set() callback 2nd arg is now struct mnt_idmap * -+ dnl # -+ AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and mnt_idmap]) -+ ZFS_LINUX_TEST_RESULT([xattr_handler_set_mnt_idmap], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_XATTR_SET_USERNS, 1, -- [xattr_handler->set() takes user_namespace]) -- ],[ -- dnl # -- dnl # 4.7 API change, -- dnl # The xattr_handler->set() callback was changed to take both -- dnl # dentry and inode. -- dnl # -- AC_MSG_RESULT(no) -- AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode]) -- ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [ -+ AC_DEFINE(HAVE_XATTR_SET_IDMAP, 1, -+ [xattr_handler->set() takes mnt_idmap]) -+ ], [ -+ AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and user_namespace]) -+ ZFS_LINUX_TEST_RESULT([xattr_handler_set_userns], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1, -- [xattr_handler->set() wants both dentry and inode]) -+ AC_DEFINE(HAVE_XATTR_SET_USERNS, 1, -+ [xattr_handler->set() takes user_namespace]) - ],[ - dnl # -- dnl # 4.4 API change, -- dnl # The xattr_handler->set() callback was changed to take a -- dnl # xattr_handler, and handler_flags argument was removed and -- dnl # should be accessed by handler->flags. -+ dnl # 4.7 API change, -+ dnl # The xattr_handler->set() callback was changed to take both -+ dnl # dentry and inode. - dnl # - AC_MSG_RESULT(no) -- AC_MSG_CHECKING( -- [whether xattr_handler->set() wants xattr_handler]) -- ZFS_LINUX_TEST_RESULT([xattr_handler_set_xattr_handler], [ -+ AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode]) -+ ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1, -- [xattr_handler->set() wants xattr_handler]) -+ AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1, -+ [xattr_handler->set() wants both dentry and inode]) - ],[ - dnl # -- dnl # 2.6.33 API change, -- dnl # The xattr_handler->set() callback was changed -- dnl # to take a dentry instead of an inode, and a -- dnl # handler_flags argument was added. -+ dnl # 4.4 API change, -+ dnl # The xattr_handler->set() callback was changed to take a -+ dnl # xattr_handler, and handler_flags argument was removed and -+ dnl # should be accessed by handler->flags. - dnl # - AC_MSG_RESULT(no) - AC_MSG_CHECKING( -- [whether xattr_handler->set() wants dentry]) -- ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry], [ -+ [whether xattr_handler->set() wants xattr_handler]) -+ ZFS_LINUX_TEST_RESULT([xattr_handler_set_xattr_handler], [ - AC_MSG_RESULT(yes) -- AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1, -- [xattr_handler->set() wants dentry]) -+ AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1, -+ [xattr_handler->set() wants xattr_handler]) - ],[ -- ZFS_LINUX_TEST_ERROR([xattr set()]) -+ dnl # -+ dnl # 2.6.33 API change, -+ dnl # The xattr_handler->set() callback was changed -+ dnl # to take a dentry instead of an inode, and a -+ dnl # handler_flags argument was added. -+ dnl # -+ AC_MSG_RESULT(no) -+ AC_MSG_CHECKING( -+ [whether xattr_handler->set() wants dentry]) -+ ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry], [ -+ AC_MSG_RESULT(yes) -+ AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1, -+ [xattr_handler->set() wants dentry]) -+ ],[ -+ ZFS_LINUX_TEST_ERROR([xattr set()]) -+ ]) - ]) - ]) - ]) -diff --git a/config/kernel.m4 b/config/kernel.m4 -index 7806da7a8..173c78a2a 100644 ---- a/config/kernel.m4 -+++ b/config/kernel.m4 -@@ -69,6 +69,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ - ZFS_AC_KERNEL_SRC_INODE_OWNER_OR_CAPABLE - ZFS_AC_KERNEL_SRC_XATTR - ZFS_AC_KERNEL_SRC_ACL -+ ZFS_AC_KERNEL_SRC_INODE_SETATTR - ZFS_AC_KERNEL_SRC_INODE_GETATTR - ZFS_AC_KERNEL_SRC_INODE_SET_FLAGS - ZFS_AC_KERNEL_SRC_INODE_SET_IVERSION -@@ -130,7 +131,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ - ZFS_AC_KERNEL_SRC_KSTRTOUL - ZFS_AC_KERNEL_SRC_PERCPU - ZFS_AC_KERNEL_SRC_CPU_HOTPLUG -- ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS -+ ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR - ZFS_AC_KERNEL_SRC_MKNOD - ZFS_AC_KERNEL_SRC_SYMLINK - ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS -@@ -144,6 +145,15 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ - ZFS_AC_KERNEL_SRC_KTHREAD - ZFS_AC_KERNEL_SRC_ZERO_PAGE - ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC -+ ZFS_AC_KERNEL_SRC_FILEMAP -+ ZFS_AC_KERNEL_SRC_WRITEPAGE_T -+ ZFS_AC_KERNEL_SRC_RECLAIMED -+ case "$host_cpu" in -+ powerpc*) -+ ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE -+ ZFS_AC_KERNEL_SRC_FLUSH_DCACHE_PAGE -+ ;; -+ esac - - AC_MSG_CHECKING([for available kernel interfaces]) - ZFS_LINUX_TEST_COMPILE_ALL([kabi]) -@@ -186,6 +196,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ - ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE - ZFS_AC_KERNEL_XATTR - ZFS_AC_KERNEL_ACL -+ ZFS_AC_KERNEL_INODE_SETATTR - ZFS_AC_KERNEL_INODE_GETATTR - ZFS_AC_KERNEL_INODE_SET_FLAGS - ZFS_AC_KERNEL_INODE_SET_IVERSION -@@ -247,7 +258,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ - ZFS_AC_KERNEL_KSTRTOUL - ZFS_AC_KERNEL_PERCPU - ZFS_AC_KERNEL_CPU_HOTPLUG -- ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS -+ ZFS_AC_KERNEL_GENERIC_FILLATTR - ZFS_AC_KERNEL_MKNOD - ZFS_AC_KERNEL_SYMLINK - ZFS_AC_KERNEL_BIO_MAX_SEGS -@@ -261,6 +272,15 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ - ZFS_AC_KERNEL_KTHREAD - ZFS_AC_KERNEL_ZERO_PAGE - ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC -+ ZFS_AC_KERNEL_FILEMAP -+ ZFS_AC_KERNEL_WRITEPAGE_T -+ ZFS_AC_KERNEL_RECLAIMED -+ case "$host_cpu" in -+ powerpc*) -+ ZFS_AC_KERNEL_CPU_HAS_FEATURE -+ ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE -+ ;; -+ esac - ]) - - dnl # -diff --git a/config/zfs-build.m4 b/config/zfs-build.m4 -index 2ab6765c3..9390812cd 100644 ---- a/config/zfs-build.m4 -+++ b/config/zfs-build.m4 -@@ -81,7 +81,7 @@ AC_DEFUN([ZFS_AC_DEBUG], [ - AC_DEFUN([ZFS_AC_DEBUGINFO_ENABLE], [ - DEBUG_CFLAGS="$DEBUG_CFLAGS -g -fno-inline $NO_IPA_SRA" - -- KERNEL_DEBUG_CFLAGS="$KERNEL_DEBUG_CFLAGS -fno-inline $NO_IPA_SRA" -+ KERNEL_DEBUG_CFLAGS="$KERNEL_DEBUG_CFLAGS -fno-inline $KERNEL_NO_IPA_SRA" - KERNEL_MAKE="$KERNEL_MAKE CONFIG_DEBUG_INFO=y" - - DEBUGINFO_ZFS="_with_debuginfo" -@@ -217,6 +217,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [ - ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_ZERO_LENGTH - ZFS_AC_CONFIG_ALWAYS_CC_NO_OMIT_FRAME_POINTER - ZFS_AC_CONFIG_ALWAYS_CC_NO_IPA_SRA -+ ZFS_AC_CONFIG_ALWAYS_KERNEL_CC_NO_IPA_SRA - ZFS_AC_CONFIG_ALWAYS_CC_ASAN - ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD - ZFS_AC_CONFIG_ALWAYS_SYSTEM -diff --git a/configure.ac b/configure.ac -index 2671434af..cb339ccd4 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -222,6 +222,7 @@ AC_CONFIG_FILES([ - tests/zfs-tests/cmd/mmap_exec/Makefile - tests/zfs-tests/cmd/mmap_libaio/Makefile - tests/zfs-tests/cmd/mmap_seek/Makefile -+ tests/zfs-tests/cmd/mmap_sync/Makefile - tests/zfs-tests/cmd/mmapwrite/Makefile - tests/zfs-tests/cmd/nvlist_to_lua/Makefile - tests/zfs-tests/cmd/randfree_file/Makefile -diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs -index 4ce739fda..3c51b53ee 100644 ---- a/contrib/initramfs/scripts/zfs -+++ b/contrib/initramfs/scripts/zfs -@@ -326,7 +326,7 @@ mount_fs() - - # Need the _original_ datasets mountpoint! - mountpoint=$(get_fs_value "$fs" mountpoint) -- ZFS_CMD="mount.zfs -o zfsutil" -+ ZFS_CMD="mount -o zfsutil -t zfs" - if [ "$mountpoint" = "legacy" ] || [ "$mountpoint" = "none" ]; then - # Can't use the mountpoint property. Might be one of our - # clones. Check the 'org.zol:mountpoint' property set in -@@ -343,7 +343,7 @@ mount_fs() - fi - # Don't use mount.zfs -o zfsutils for legacy mountpoint - if [ "$mountpoint" = "legacy" ]; then -- ZFS_CMD="mount.zfs" -+ ZFS_CMD="mount -t zfs" - fi - # Last hail-mary: Hope 'rootmnt' is set! - mountpoint="" -@@ -914,7 +914,7 @@ mountroot() - echo " not specified on the kernel command line." - echo "" - echo "Manually mount the root filesystem on $rootmnt and then exit." -- echo "Hint: Try: mount.zfs -o zfsutil ${ZFS_RPOOL-rpool}/ROOT/system $rootmnt" -+ echo "Hint: Try: mount -o zfsutil -t zfs ${ZFS_RPOOL-rpool}/ROOT/system $rootmnt" - shell - fi - -diff --git a/contrib/pam_zfs_key/pam_zfs_key.c b/contrib/pam_zfs_key/pam_zfs_key.c -index 0db119382..313703770 100644 ---- a/contrib/pam_zfs_key/pam_zfs_key.c -+++ b/contrib/pam_zfs_key/pam_zfs_key.c -@@ -548,16 +548,11 @@ zfs_key_config_modify_session_counter(pam_handle_t *pamh, - errno); - return (-1); - } -- size_t runtime_path_len = strlen(runtime_path); -- size_t counter_path_len = runtime_path_len + 1 + 10; -- char *counter_path = malloc(counter_path_len + 1); -- if (!counter_path) { -+ -+ char *counter_path; -+ if (asprintf(&counter_path, "%s/%u", runtime_path, config->uid) == -1) - return (-1); -- } -- counter_path[0] = 0; -- strcat(counter_path, runtime_path); -- snprintf(counter_path + runtime_path_len, counter_path_len, "/%d", -- config->uid); -+ - const int fd = open(counter_path, - O_RDWR | O_CLOEXEC | O_CREAT | O_NOFOLLOW, - S_IRUSR | S_IWUSR); -diff --git a/include/os/freebsd/zfs/sys/zfs_znode_impl.h b/include/os/freebsd/zfs/sys/zfs_znode_impl.h -index 3d93525b4..120884116 100644 ---- a/include/os/freebsd/zfs/sys/zfs_znode_impl.h -+++ b/include/os/freebsd/zfs/sys/zfs_znode_impl.h -@@ -118,7 +118,8 @@ extern minor_t zfsdev_minor_alloc(void); - #define Z_ISLNK(type) ((type) == VLNK) - #define Z_ISDIR(type) ((type) == VDIR) - --#define zn_has_cached_data(zp) vn_has_cached_data(ZTOV(zp)) -+#define zn_has_cached_data(zp, start, end) \ -+ vn_has_cached_data(ZTOV(zp)) - #define zn_flush_cached_data(zp, sync) vn_flush_cached_data(ZTOV(zp), sync) - #define zn_rlimit_fsize(zp, uio) \ - vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio)) -diff --git a/include/os/linux/kernel/linux/dcache_compat.h b/include/os/linux/kernel/linux/dcache_compat.h -index c90135fd3..f87f1653a 100644 ---- a/include/os/linux/kernel/linux/dcache_compat.h -+++ b/include/os/linux/kernel/linux/dcache_compat.h -@@ -39,6 +39,21 @@ - #define d_alias d_u.d_alias - #endif - -+/* -+ * Starting from Linux 5.13, flush_dcache_page() becomes an inline function -+ * and under some configurations, may indirectly referencing GPL-only -+ * cpu_feature_keys on powerpc. Override this function when it is detected -+ * being GPL-only. -+ */ -+#if defined __powerpc__ && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY -+#include -+#define flush_dcache_page(page) do { \ -+ if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && \ -+ test_bit(PG_dcache_clean, &(page)->flags)) \ -+ clear_bit(PG_dcache_clean, &(page)->flags); \ -+ } while (0) -+#endif -+ - /* - * 2.6.30 API change, - * The const keyword was added to the 'struct dentry_operations' in -diff --git a/include/os/linux/kernel/linux/simd_powerpc.h b/include/os/linux/kernel/linux/simd_powerpc.h -index 108cef22f..422b85af3 100644 ---- a/include/os/linux/kernel/linux/simd_powerpc.h -+++ b/include/os/linux/kernel/linux/simd_powerpc.h -@@ -76,6 +76,17 @@ - #define kfpu_init() 0 - #define kfpu_fini() ((void) 0) - -+/* -+ * Linux 4.7 makes cpu_has_feature to use jump labels on powerpc if -+ * CONFIG_JUMP_LABEL_FEATURE_CHECKS is enabled, in this case however it -+ * references GPL-only symbol cpu_feature_keys. Therefore we overrides this -+ * interface when it is detected being GPL-only. -+ */ -+#if defined(CONFIG_JUMP_LABEL_FEATURE_CHECKS) && \ -+ defined(HAVE_CPU_HAS_FEATURE_GPL_ONLY) -+#define cpu_has_feature(feature) early_cpu_has_feature(feature) -+#endif -+ - /* - * Check if AltiVec instruction set is available - */ -diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h -index 91e908598..e82bbf755 100644 ---- a/include/os/linux/kernel/linux/vfs_compat.h -+++ b/include/os/linux/kernel/linux/vfs_compat.h -@@ -344,7 +344,8 @@ static inline void zfs_gid_write(struct inode *ip, gid_t gid) - * 4.9 API change - */ - #if !(defined(HAVE_SETATTR_PREPARE_NO_USERNS) || \ -- defined(HAVE_SETATTR_PREPARE_USERNS)) -+ defined(HAVE_SETATTR_PREPARE_USERNS) || \ -+ defined(HAVE_SETATTR_PREPARE_IDMAP)) - static inline int - setattr_prepare(struct dentry *dentry, struct iattr *ia) - { -@@ -399,6 +400,15 @@ func(struct user_namespace *user_ns, const struct path *path, \ - return (func##_impl(user_ns, path, stat, request_mask, \ - query_flags)); \ - } -+#elif defined(HAVE_IDMAP_IOPS_GETATTR) -+#define ZPL_GETATTR_WRAPPER(func) \ -+static int \ -+func(struct mnt_idmap *user_ns, const struct path *path, \ -+ struct kstat *stat, u32 request_mask, unsigned int query_flags) \ -+{ \ -+ return (func##_impl(user_ns, path, stat, request_mask, \ -+ query_flags)); \ -+} - #else - #error - #endif -@@ -450,8 +460,15 @@ zpl_is_32bit_api(void) - * 5.12 API change - * To support id-mapped mounts, generic_fillattr() was modified to - * accept a new struct user_namespace* as its first arg. -+ * -+ * 6.3 API change -+ * generic_fillattr() first arg is changed to struct mnt_idmap * -+ * - */ --#ifdef HAVE_GENERIC_FILLATTR_USERNS -+#ifdef HAVE_GENERIC_FILLATTR_IDMAP -+#define zpl_generic_fillattr(idmap, ip, sp) \ -+ generic_fillattr(idmap, ip, sp) -+#elif defined(HAVE_GENERIC_FILLATTR_USERNS) - #define zpl_generic_fillattr(user_ns, ip, sp) \ - generic_fillattr(user_ns, ip, sp) - #else -diff --git a/include/os/linux/kernel/linux/xattr_compat.h b/include/os/linux/kernel/linux/xattr_compat.h -index 30403fe87..3ffd00169 100644 ---- a/include/os/linux/kernel/linux/xattr_compat.h -+++ b/include/os/linux/kernel/linux/xattr_compat.h -@@ -133,20 +133,35 @@ fn(const struct xattr_handler *handler, struct dentry *dentry, \ - #error "Unsupported kernel" - #endif - -+/* -+ * 6.3 API change, -+ * The xattr_handler->set() callback was changed to take the -+ * struct mnt_idmap* as the first arg, to support idmapped -+ * mounts. -+ */ -+#if defined(HAVE_XATTR_SET_IDMAP) -+#define ZPL_XATTR_SET_WRAPPER(fn) \ -+static int \ -+fn(const struct xattr_handler *handler, struct mnt_idmap *user_ns, \ -+ struct dentry *dentry, struct inode *inode, const char *name, \ -+ const void *buffer, size_t size, int flags) \ -+{ \ -+ return (__ ## fn(user_ns, inode, name, buffer, size, flags)); \ -+} - /* - * 5.12 API change, - * The xattr_handler->set() callback was changed to take the - * struct user_namespace* as the first arg, to support idmapped - * mounts. - */ --#if defined(HAVE_XATTR_SET_USERNS) -+#elif defined(HAVE_XATTR_SET_USERNS) - #define ZPL_XATTR_SET_WRAPPER(fn) \ - static int \ - fn(const struct xattr_handler *handler, struct user_namespace *user_ns, \ - struct dentry *dentry, struct inode *inode, const char *name, \ - const void *buffer, size_t size, int flags) \ - { \ -- return (__ ## fn(inode, name, buffer, size, flags)); \ -+ return (__ ## fn(user_ns, inode, name, buffer, size, flags)); \ - } - /* - * 4.7 API change, -@@ -160,7 +175,7 @@ fn(const struct xattr_handler *handler, struct dentry *dentry, \ - struct inode *inode, const char *name, const void *buffer, \ - size_t size, int flags) \ - { \ -- return (__ ## fn(inode, name, buffer, size, flags)); \ -+ return (__ ## fn(kcred->user_ns, inode, name, buffer, size, flags));\ - } - /* - * 4.4 API change, -@@ -174,7 +189,8 @@ static int \ - fn(const struct xattr_handler *handler, struct dentry *dentry, \ - const char *name, const void *buffer, size_t size, int flags) \ - { \ -- return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \ -+ return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \ -+ buffer, size, flags)); \ - } - /* - * 2.6.33 API change, -@@ -187,7 +203,8 @@ static int \ - fn(struct dentry *dentry, const char *name, const void *buffer, \ - size_t size, int flags, int unused_handler_flags) \ - { \ -- return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \ -+ return (__ ## fn(kcred->user_ns, dentry->d_inode, name, buffer, \ -+ size, flags)); \ - } - #else - #error "Unsupported kernel" -diff --git a/include/os/linux/spl/sys/cred.h b/include/os/linux/spl/sys/cred.h -index b7d3f38d7..501bd4566 100644 ---- a/include/os/linux/spl/sys/cred.h -+++ b/include/os/linux/spl/sys/cred.h -@@ -45,6 +45,8 @@ typedef struct cred cred_t; - #define SGID_TO_KGID(x) (KGIDT_INIT(x)) - #define KGIDP_TO_SGIDP(x) (&(x)->val) - -+extern zidmap_t *zfs_get_init_idmap(void); -+ - extern void crhold(cred_t *cr); - extern void crfree(cred_t *cr); - extern uid_t crgetuid(const cred_t *cr); -diff --git a/include/os/linux/spl/sys/types.h b/include/os/linux/spl/sys/types.h -index b44c94518..4d638efbb 100644 ---- a/include/os/linux/spl/sys/types.h -+++ b/include/os/linux/spl/sys/types.h -@@ -54,4 +54,18 @@ typedef ulong_t pgcnt_t; - typedef int major_t; - typedef int minor_t; - -+struct user_namespace; -+#ifdef HAVE_IOPS_CREATE_IDMAP -+#include -+struct mnt_idmap { -+ struct user_namespace *owner; -+ refcount_t count; -+}; -+typedef struct mnt_idmap zidmap_t; -+#else -+typedef struct user_namespace zidmap_t; -+#endif -+ -+extern zidmap_t *zfs_init_idmap; -+ - #endif /* _SPL_TYPES_H */ -diff --git a/include/os/linux/zfs/sys/trace_acl.h b/include/os/linux/zfs/sys/trace_acl.h -index 21bcefa4e..656552749 100644 ---- a/include/os/linux/zfs/sys/trace_acl.h -+++ b/include/os/linux/zfs/sys/trace_acl.h -@@ -58,9 +58,10 @@ DECLARE_EVENT_CLASS(zfs_ace_class, - __field(uint64_t, z_size) - __field(uint64_t, z_pflags) - __field(uint32_t, z_sync_cnt) -+ __field(uint32_t, z_sync_writes_cnt) -+ __field(uint32_t, z_async_writes_cnt) - __field(mode_t, z_mode) - __field(boolean_t, z_is_sa) -- __field(boolean_t, z_is_mapped) - __field(boolean_t, z_is_ctldir) - - __field(uint32_t, i_uid) -@@ -90,9 +91,10 @@ DECLARE_EVENT_CLASS(zfs_ace_class, - __entry->z_size = zn->z_size; - __entry->z_pflags = zn->z_pflags; - __entry->z_sync_cnt = zn->z_sync_cnt; -+ __entry->z_sync_writes_cnt = zn->z_sync_writes_cnt; -+ __entry->z_async_writes_cnt = zn->z_async_writes_cnt; - __entry->z_mode = zn->z_mode; - __entry->z_is_sa = zn->z_is_sa; -- __entry->z_is_mapped = zn->z_is_mapped; - __entry->z_is_ctldir = zn->z_is_ctldir; - - __entry->i_uid = KUID_TO_SUID(ZTOI(zn)->i_uid); -@@ -114,18 +116,18 @@ DECLARE_EVENT_CLASS(zfs_ace_class, - TP_printk("zn { id %llu unlinked %u atime_dirty %u " - "zn_prefetch %u blksz %u seq %u " - "mapcnt %llu size %llu pflags %llu " -- "sync_cnt %u mode 0x%x is_sa %d " -- "is_mapped %d is_ctldir %d inode { " -- "uid %u gid %u ino %lu nlink %u size %lli " -+ "sync_cnt %u sync_writes_cnt %u async_writes_cnt %u " -+ "mode 0x%x is_sa %d is_ctldir %d " -+ "inode { uid %u gid %u ino %lu nlink %u size %lli " - "blkbits %u bytes %u mode 0x%x generation %x } } " - "ace { type %u flags %u access_mask %u } mask_matched %u", - __entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty, - __entry->z_zn_prefetch, __entry->z_blksz, - __entry->z_seq, __entry->z_mapcnt, __entry->z_size, -- __entry->z_pflags, __entry->z_sync_cnt, __entry->z_mode, -- __entry->z_is_sa, __entry->z_is_mapped, -- __entry->z_is_ctldir, __entry->i_uid, -- __entry->i_gid, __entry->i_ino, __entry->i_nlink, -+ __entry->z_pflags, __entry->z_sync_cnt, -+ __entry->z_sync_writes_cnt, __entry->z_async_writes_cnt, -+ __entry->z_mode, __entry->z_is_sa, __entry->z_is_ctldir, -+ __entry->i_uid, __entry->i_gid, __entry->i_ino, __entry->i_nlink, - __entry->i_size, __entry->i_blkbits, - __entry->i_bytes, __entry->i_mode, __entry->i_generation, - __entry->z_type, __entry->z_flags, __entry->z_access_mask, -diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h -index 47f91e4a6..331f2e2bc 100644 ---- a/include/os/linux/zfs/sys/zfs_vnops_os.h -+++ b/include/os/linux/zfs/sys/zfs_vnops_os.h -@@ -54,8 +54,7 @@ extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, - extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, - cred_t *cr, int flags); - extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr); --extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip, -- struct kstat *sp); -+extern int zfs_getattr_fast(zidmap_t *, struct inode *ip, struct kstat *sp); - extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr); - extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, - char *tnm, cred_t *cr, int flags); -@@ -68,9 +67,9 @@ extern void zfs_inactive(struct inode *ip); - extern int zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag, - offset_t offset, cred_t *cr); - extern int zfs_fid(struct inode *ip, fid_t *fidp); --extern int zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages); -+extern int zfs_getpage(struct inode *ip, struct page *pp); - extern int zfs_putpage(struct inode *ip, struct page *pp, -- struct writeback_control *wbc); -+ struct writeback_control *wbc, boolean_t for_sync); - extern int zfs_dirty_inode(struct inode *ip, int flags); - extern int zfs_map(struct inode *ip, offset_t off, caddr_t *addrp, - size_t len, unsigned long vm_flags); -diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h -index de46fc8f2..9b9ac7a4f 100644 ---- a/include/os/linux/zfs/sys/zfs_znode_impl.h -+++ b/include/os/linux/zfs/sys/zfs_znode_impl.h -@@ -47,9 +47,16 @@ - extern "C" { - #endif - -+#if defined(HAVE_FILEMAP_RANGE_HAS_PAGE) - #define ZNODE_OS_FIELDS \ - inode_timespec_t z_btime; /* creation/birth time (cached) */ \ - struct inode z_inode; -+#else -+#define ZNODE_OS_FIELDS \ -+ inode_timespec_t z_btime; /* creation/birth time (cached) */ \ -+ struct inode z_inode; \ -+ boolean_t z_is_mapped; /* we are mmap'ed */ -+#endif - - /* - * Convert between znode pointers and inode pointers -@@ -70,7 +77,14 @@ extern "C" { - #define Z_ISDEV(type) (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type)) - #define Z_ISDIR(type) S_ISDIR(type) - --#define zn_has_cached_data(zp) ((zp)->z_is_mapped) -+#if defined(HAVE_FILEMAP_RANGE_HAS_PAGE) -+#define zn_has_cached_data(zp, start, end) \ -+ filemap_range_has_page(ZTOI(zp)->i_mapping, start, end) -+#else -+#define zn_has_cached_data(zp, start, end) \ -+ ((zp)->z_is_mapped) -+#endif -+ - #define zn_flush_cached_data(zp, sync) write_inode_now(ZTOI(zp), sync) - #define zn_rlimit_fsize(zp, uio) (0) - -diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h -index ac9815d4e..4e08470e7 100644 ---- a/include/os/linux/zfs/sys/zpl.h -+++ b/include/os/linux/zfs/sys/zpl.h -@@ -64,7 +64,10 @@ extern int zpl_xattr_security_init(struct inode *ip, struct inode *dip, - const struct qstr *qstr); - #if defined(CONFIG_FS_POSIX_ACL) - #if defined(HAVE_SET_ACL) --#if defined(HAVE_SET_ACL_USERNS) -+#if defined(HAVE_SET_ACL_IDMAP_DENTRY) -+extern int zpl_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, -+ struct posix_acl *acl, int type); -+#elif defined(HAVE_SET_ACL_USERNS) - extern int zpl_set_acl(struct user_namespace *userns, struct inode *ip, - struct posix_acl *acl, int type); - #elif defined(HAVE_SET_ACL_USERNS_DENTRY_ARG2) -@@ -186,13 +189,15 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx) - - #if defined(HAVE_INODE_OWNER_OR_CAPABLE) - #define zpl_inode_owner_or_capable(ns, ip) inode_owner_or_capable(ip) --#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_IDMAPPED) -+#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_USERNS) - #define zpl_inode_owner_or_capable(ns, ip) inode_owner_or_capable(ns, ip) -+#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_IDMAP) -+#define zpl_inode_owner_or_capable(idmap, ip) inode_owner_or_capable(idmap, ip) - #else - #error "Unsupported kernel" - #endif - --#ifdef HAVE_SETATTR_PREPARE_USERNS -+#if defined(HAVE_SETATTR_PREPARE_USERNS) || defined(HAVE_SETATTR_PREPARE_IDMAP) - #define zpl_setattr_prepare(ns, dentry, ia) setattr_prepare(ns, dentry, ia) - #else - /* -diff --git a/include/sys/dmu.h b/include/sys/dmu.h -index 7bdd42e8b..12bd88720 100644 ---- a/include/sys/dmu.h -+++ b/include/sys/dmu.h -@@ -778,6 +778,9 @@ dmu_tx_t *dmu_tx_create(objset_t *os); - void dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len); - void dmu_tx_hold_write_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, - int len); -+void dmu_tx_hold_append(dmu_tx_t *tx, uint64_t object, uint64_t off, int len); -+void dmu_tx_hold_append_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, -+ int len); - void dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, - uint64_t len); - void dmu_tx_hold_free_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, -diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h -index 7ade2dc91..fffcbcfca 100644 ---- a/include/sys/dmu_objset.h -+++ b/include/sys/dmu_objset.h -@@ -72,6 +72,10 @@ struct dmu_tx; - */ - #define OBJSET_CRYPT_PORTABLE_FLAGS_MASK (0) - -+#if defined(__clang__) -+#pragma clang diagnostic push -+#pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end" -+#endif - typedef struct objset_phys { - dnode_phys_t os_meta_dnode; - zil_header_t os_zil_header; -@@ -88,6 +92,9 @@ typedef struct objset_phys { - char os_pad1[OBJSET_PHYS_SIZE_V3 - OBJSET_PHYS_SIZE_V2 - - sizeof (dnode_phys_t)]; - } objset_phys_t; -+#if defined(__clang__) -+#pragma clang diagnostic pop -+#endif - - typedef int (*dmu_objset_upgrade_cb_t)(objset_t *); - -diff --git a/include/sys/dmu_tx.h b/include/sys/dmu_tx.h -index ad3f1b0e4..e8886fd4e 100644 ---- a/include/sys/dmu_tx.h -+++ b/include/sys/dmu_tx.h -@@ -90,6 +90,7 @@ enum dmu_tx_hold_type { - THT_ZAP, - THT_SPACE, - THT_SPILL, -+ THT_APPEND, - THT_NUMTYPES - }; - -diff --git a/include/sys/dnode.h b/include/sys/dnode.h -index 20b7c2aaf..39bbdae44 100644 ---- a/include/sys/dnode.h -+++ b/include/sys/dnode.h -@@ -120,7 +120,11 @@ extern "C" { - #define DN_MAX_LEVELS (DIV_ROUND_UP(DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT, \ - DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT) + 1) - --#define DN_BONUS(dnp) ((void*)((dnp)->dn_bonus + \ -+/* -+ * Use the flexible array instead of the fixed length one dn_bonus -+ * to address memcpy/memmove fortify error -+ */ -+#define DN_BONUS(dnp) ((void*)((dnp)->dn_bonus_flexible + \ - (((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t)))) - #define DN_MAX_BONUS_LEN(dnp) \ - ((dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ? \ -@@ -266,6 +270,10 @@ typedef struct dnode_phys { - sizeof (blkptr_t)]; - blkptr_t dn_spill; - }; -+ struct { -+ blkptr_t __dn_ignore4; -+ uint8_t dn_bonus_flexible[]; -+ }; - }; - } dnode_phys_t; - -diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h -index 111e70ece..84f5aee59 100644 ---- a/include/sys/fs/zfs.h -+++ b/include/sys/fs/zfs.h -@@ -1173,6 +1173,7 @@ typedef enum pool_initialize_func { - POOL_INITIALIZE_START, - POOL_INITIALIZE_CANCEL, - POOL_INITIALIZE_SUSPEND, -+ POOL_INITIALIZE_UNINIT, - POOL_INITIALIZE_FUNCS - } pool_initialize_func_t; - -diff --git a/include/sys/spa.h b/include/sys/spa.h -index fedadab45..42f7fec0f 100644 ---- a/include/sys/spa.h -+++ b/include/sys/spa.h -@@ -785,6 +785,7 @@ extern int bpobj_enqueue_free_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx); - #define SPA_ASYNC_L2CACHE_REBUILD 0x800 - #define SPA_ASYNC_L2CACHE_TRIM 0x1000 - #define SPA_ASYNC_REBUILD_DONE 0x2000 -+#define SPA_ASYNC_DETACH_SPARE 0x4000 - - /* device manipulation */ - extern int spa_vdev_add(spa_t *spa, nvlist_t *nvroot); -@@ -971,6 +972,8 @@ extern int spa_import_progress_set_state(uint64_t pool_guid, - /* Pool configuration locks */ - extern int spa_config_tryenter(spa_t *spa, int locks, 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, -+ 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/include/sys/vdev_initialize.h b/include/sys/vdev_initialize.h -index 81d39ebeb..942fc71c5 100644 ---- a/include/sys/vdev_initialize.h -+++ b/include/sys/vdev_initialize.h -@@ -33,6 +33,7 @@ extern "C" { - #endif - - extern void vdev_initialize(vdev_t *vd); -+extern void vdev_uninitialize(vdev_t *vd); - extern void vdev_initialize_stop(vdev_t *vd, - vdev_initializing_state_t tgt_state, list_t *vd_list); - extern void vdev_initialize_stop_all(vdev_t *vd, -diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h -index 0df8a0e4b..48dab671d 100644 ---- a/include/sys/zfs_znode.h -+++ b/include/sys/zfs_znode.h -@@ -188,7 +188,6 @@ typedef struct znode { - boolean_t z_atime_dirty; /* atime needs to be synced */ - boolean_t z_zn_prefetch; /* Prefetch znodes? */ - boolean_t z_is_sa; /* are we native sa? */ -- boolean_t z_is_mapped; /* are we mmap'ed */ - boolean_t z_is_ctldir; /* are we .zfs entry */ - boolean_t z_suspended; /* extra ref from a suspend? */ - uint_t z_blksz; /* block size in bytes */ -@@ -198,6 +197,8 @@ typedef struct znode { - uint64_t z_size; /* file size (cached) */ - uint64_t z_pflags; /* pflags (cached) */ - uint32_t z_sync_cnt; /* synchronous open count */ -+ uint32_t z_sync_writes_cnt; /* synchronous write count */ -+ uint32_t z_async_writes_cnt; /* asynchronous write count */ - mode_t z_mode; /* mode (cached) */ - kmutex_t z_acl_lock; /* acl data lock */ - zfs_acl_t *z_acl_cached; /* cached acl */ -diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi -index 13ce19df9..58c2d7635 100644 ---- a/lib/libzfs/libzfs.abi -+++ b/lib/libzfs/libzfs.abi -@@ -5410,7 +5410,8 @@ - - - -- -+ -+ - - - -diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c -index f2219d1c3..f6d844bdf 100644 ---- a/lib/libzfs/libzfs_dataset.c -+++ b/lib/libzfs/libzfs_dataset.c -@@ -1017,6 +1017,7 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, - nvlist_t *ret; - int chosen_normal = -1; - int chosen_utf = -1; -+ int set_maxbs = 0; - - if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { - (void) no_memory(hdl); -@@ -1234,12 +1235,17 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, - (void) zfs_error(hdl, EZFS_BADPROP, errbuf); - goto error; - } -+ /* save the ZFS_PROP_RECORDSIZE during create op */ -+ if (zpool_hdl == NULL && prop == ZFS_PROP_RECORDSIZE) { -+ set_maxbs = intval; -+ } - break; - } - - case ZFS_PROP_SPECIAL_SMALL_BLOCKS: - { -- int maxbs = SPA_OLD_MAXBLOCKSIZE; -+ int maxbs = -+ set_maxbs == 0 ? SPA_OLD_MAXBLOCKSIZE : set_maxbs; - char buf[64]; - - if (zpool_hdl != NULL) { -diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c -index 29f077841..fc6c6e8e2 100644 ---- a/lib/libzfs/libzfs_pool.c -+++ b/lib/libzfs/libzfs_pool.c -@@ -2224,8 +2224,8 @@ xlate_init_err(int err) - } - - /* -- * Begin, suspend, or cancel the initialization (initializing of all free -- * blocks) for the given vdevs in the given pool. -+ * Begin, suspend, cancel, or uninit (clear) the initialization (initializing -+ * of all free blocks) for the given vdevs in the given pool. - */ - static int - zpool_initialize_impl(zpool_handle_t *zhp, pool_initialize_func_t cmd_type, -@@ -2251,11 +2251,16 @@ zpool_initialize_impl(zpool_handle_t *zhp, pool_initialize_func_t cmd_type, - vdev_guids, &errlist); - - if (err != 0) { -- if (errlist != NULL) { -- vd_errlist = fnvlist_lookup_nvlist(errlist, -- ZPOOL_INITIALIZE_VDEVS); -+ if (errlist != NULL && nvlist_lookup_nvlist(errlist, -+ ZPOOL_INITIALIZE_VDEVS, &vd_errlist) == 0) { - goto list_errors; - } -+ -+ if (err == EINVAL && cmd_type == POOL_INITIALIZE_UNINIT) { -+ zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, -+ "uninitialize is not supported by kernel")); -+ } -+ - (void) zpool_standard_error(zhp->zpool_hdl, err, - dgettext(TEXT_DOMAIN, "operation failed")); - goto out; -diff --git a/lib/libzfs_core/libzfs_core.abi b/lib/libzfs_core/libzfs_core.abi -index 1b03a5c42..7ede3e097 100644 ---- a/lib/libzfs_core/libzfs_core.abi -+++ b/lib/libzfs_core/libzfs_core.abi -@@ -1726,7 +1726,8 @@ - - - -- -+ -+ - - - -diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 -index 71a95c3bd..0c60a9c8e 100644 ---- a/man/man4/zfs.4 -+++ b/man/man4/zfs.4 -@@ -1712,7 +1712,7 @@ completes in order to verify the checksums of all blocks which have been - resilvered. - This is enabled by default and strongly recommended. - . --.It Sy zfs_rebuild_vdev_limit Ns = Ns Sy 33554432 Ns B Po 32MB Pc Pq ulong -+.It Sy zfs_rebuild_vdev_limit Ns = Ns Sy 67108864 Ns B Po 64 MiB Pc Pq ulong - Maximum amount of I/O that can be concurrently issued for a sequential - resilver per leaf device, given in bytes. - . -@@ -1831,6 +1831,13 @@ When we cross this limit from above it is because we are issuing verification I/ - In this case (unless the metadata scan is done) we stop issuing verification I/O - and start scanning metadata again until we get to the hard limit. - . -+.It Sy zfs_scan_report_txgs Ns = Ns Sy 0 Ns | Ns 1 Pq uint -+When reporting resilver throughput and estimated completion time use the -+performance observed over roughly the last -+.Sy zfs_scan_report_txgs -+TXGs. -+When set to zero performance is calculated over the time between checkpoints. -+. - .It Sy zfs_scan_strict_mem_lim Ns = Ns Sy 0 Ns | Ns 1 Pq int - Enforce tight memory limits on pool scans when a sequential scan is in progress. - When disabled, the memory limit may be exceeded by fast disks. -@@ -1839,7 +1846,7 @@ When disabled, the memory limit may be exceeded by fast disks. - Freezes a scrub/resilver in progress without actually pausing it. - Intended for testing/debugging. - . --.It Sy zfs_scan_vdev_limit Ns = Ns Sy 4194304 Ns B Po 4MB Pc Pq int -+.It Sy zfs_scan_vdev_limit Ns = Ns Sy 16777216 Ns B Po 16 MiB Pc Pq int - Maximum amount of data that can be concurrently issued at once for scrubs and - resilvers per leaf device, given in bytes. - . -diff --git a/man/man8/zpool-initialize.8 b/man/man8/zpool-initialize.8 -index 0a108180d..ada00bb1b 100644 ---- a/man/man8/zpool-initialize.8 -+++ b/man/man8/zpool-initialize.8 -@@ -36,7 +36,7 @@ - .Sh SYNOPSIS - .Nm zpool - .Cm initialize --.Op Fl c Ns | Ns Fl s -+.Op Fl c Ns | Ns Fl s | Ns Fl u - .Op Fl w - .Ar pool - .Oo Ar device Oc Ns … -@@ -60,6 +60,14 @@ initialized, the command will fail and no suspension will occur on any device. - Initializing can then be resumed by running - .Nm zpool Cm initialize - with no flags on the relevant target devices. -+.It Fl u , -uninit -+Clears the initialization state on the specified devices, or all eligible -+devices if none are specified. -+If the devices are being actively initialized the command will fail. -+After being cleared -+.Nm zpool Cm initialize -+with no flags can be used to re-initialize all unallocoated regions on -+the relevant target devices. - .It Fl w , -wait - Wait until the devices have finished initializing before returning. - .El -diff --git a/module/Kbuild.in b/module/Kbuild.in -index 1507965c5..7675d614f 100644 ---- a/module/Kbuild.in -+++ b/module/Kbuild.in -@@ -44,4 +44,5 @@ endif - subdir-asflags-y := $(ZFS_MODULE_CFLAGS) $(ZFS_MODULE_CPPFLAGS) - subdir-ccflags-y := $(ZFS_MODULE_CFLAGS) $(ZFS_MODULE_CPPFLAGS) - -+ - endif -diff --git a/module/icp/algs/edonr/edonr.c b/module/icp/algs/edonr/edonr.c -index 7a3ba30c0..baf8bb885 100644 ---- a/module/icp/algs/edonr/edonr.c -+++ b/module/icp/algs/edonr/edonr.c -@@ -343,9 +343,11 @@ Q256(size_t bitlen, const uint32_t *data, uint32_t *restrict p) - * which only goes over it by a hair (1248 bytes on ARM32). - */ - #include /* for _ILP32 */ --#ifdef _ILP32 /* We're 32-bit, assume small stack frames */ -+#if defined(_ILP32) /* We're 32-bit, assume small stack frames */ -+#if defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic ignored "-Wframe-larger-than=" - #endif -+#endif - - #if defined(__IBMC__) && defined(_AIX) && defined(__64BIT__) - static inline size_t -diff --git a/module/icp/algs/skein/skein_block.c b/module/icp/algs/skein/skein_block.c -index 7ba165a48..3ad52da5f 100644 ---- a/module/icp/algs/skein/skein_block.c -+++ b/module/icp/algs/skein/skein_block.c -@@ -30,7 +30,9 @@ - * the #pragma here to ignore the warning. - */ - #if defined(_ILP32) || defined(__powerpc) /* Assume small stack */ -+#if defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic ignored "-Wframe-larger-than=" -+#endif - /* - * We're running on 32-bit, don't unroll loops to save stack frame space - * -diff --git a/module/lua/ldo.c b/module/lua/ldo.c -index a9835c4f5..e4abe04e9 100644 ---- a/module/lua/ldo.c -+++ b/module/lua/ldo.c -@@ -197,7 +197,8 @@ l_noret luaD_throw (lua_State *L, int errcode) { - } - } - --#if defined(HAVE_INFINITE_RECURSION) -+#if defined(__GNUC__) && !defined(__clang__) && \ -+ defined(HAVE_INFINITE_RECURSION) - #pragma GCC diagnostic pop - #endif - -diff --git a/module/os/freebsd/zfs/zfs_ctldir.c b/module/os/freebsd/zfs/zfs_ctldir.c -index 5bd2e1510..cfc4bab2f 100644 ---- a/module/os/freebsd/zfs/zfs_ctldir.c -+++ b/module/os/freebsd/zfs/zfs_ctldir.c -@@ -204,6 +204,10 @@ sfs_vgetx(struct mount *mp, int flags, uint64_t parent_id, uint64_t id, - return (error); - } - -+#if __FreeBSD_version >= 1400077 -+ vn_set_state(vp, VSTATE_CONSTRUCTED); -+#endif -+ - *vpp = vp; - return (0); - } -@@ -675,6 +679,17 @@ zfsctl_root_readdir(struct vop_readdir_args *ap) - - ASSERT3S(vp->v_type, ==, VDIR); - -+ /* -+ * FIXME: this routine only ever emits 3 entries and does not tolerate -+ * being called with a buffer too small to handle all of them. -+ * -+ * The check below facilitates the idiom of repeating calls until the -+ * count to return is 0. -+ */ -+ if (zfs_uio_offset(&uio) == 3 * sizeof (entry)) { -+ return (0); -+ } -+ - error = sfs_readdir_common(zfsvfs->z_root, ZFSCTL_INO_ROOT, ap, &uio, - &dots_offset); - if (error != 0) { -@@ -800,6 +815,9 @@ static struct vop_vector zfsctl_ops_root = { - .vop_default = &default_vnodeops, - #if __FreeBSD_version >= 1300121 - .vop_fplookup_vexec = VOP_EAGAIN, -+#endif -+#if __FreeBSD_version >= 1300139 -+ .vop_fplookup_symlink = VOP_EAGAIN, - #endif - .vop_open = zfsctl_common_open, - .vop_close = zfsctl_common_close, -@@ -1126,6 +1144,9 @@ static struct vop_vector zfsctl_ops_snapdir = { - .vop_default = &default_vnodeops, - #if __FreeBSD_version >= 1300121 - .vop_fplookup_vexec = VOP_EAGAIN, -+#endif -+#if __FreeBSD_version >= 1300139 -+ .vop_fplookup_symlink = VOP_EAGAIN, - #endif - .vop_open = zfsctl_common_open, - .vop_close = zfsctl_common_close, -@@ -1150,7 +1171,7 @@ zfsctl_snapshot_inactive(struct vop_inactive_args *ap) - { - vnode_t *vp = ap->a_vp; - -- VERIFY3S(vrecycle(vp), ==, 1); -+ vrecycle(vp); - return (0); - } - -@@ -1234,6 +1255,11 @@ static struct vop_vector zfsctl_ops_snapshot = { - #if __FreeBSD_version >= 1300121 - .vop_fplookup_vexec = VOP_EAGAIN, - #endif -+#if __FreeBSD_version >= 1300139 -+ .vop_fplookup_symlink = VOP_EAGAIN, -+#endif -+ .vop_open = zfsctl_common_open, -+ .vop_close = zfsctl_common_close, - .vop_inactive = zfsctl_snapshot_inactive, - #if __FreeBSD_version >= 1300045 - .vop_need_inactive = vop_stdneed_inactive, -diff --git a/module/os/freebsd/zfs/zfs_ioctl_os.c b/module/os/freebsd/zfs/zfs_ioctl_os.c -index 7f7e2b72c..effc11518 100644 ---- a/module/os/freebsd/zfs/zfs_ioctl_os.c -+++ b/module/os/freebsd/zfs/zfs_ioctl_os.c -@@ -59,7 +59,7 @@ zfs_vfs_ref(zfsvfs_t **zfvp) - return (error); - } - --int -+boolean_t - zfs_vfs_held(zfsvfs_t *zfsvfs) - { - return (zfsvfs->z_vfs != NULL); -diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c -index 1debc3ec3..92e3bdd2e 100644 ---- a/module/os/freebsd/zfs/zfs_znode.c -+++ b/module/os/freebsd/zfs/zfs_znode.c -@@ -153,6 +153,9 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) - zp->z_xattr_cached = NULL; - zp->z_xattr_parent = 0; - zp->z_vnode = NULL; -+ zp->z_sync_writes_cnt = 0; -+ zp->z_async_writes_cnt = 0; -+ - return (0); - } - -@@ -172,6 +175,9 @@ zfs_znode_cache_destructor(void *buf, void *arg) - - ASSERT3P(zp->z_acl_cached, ==, NULL); - ASSERT3P(zp->z_xattr_cached, ==, NULL); -+ -+ ASSERT0(atomic_load_32(&zp->z_sync_writes_cnt)); -+ ASSERT0(atomic_load_32(&zp->z_async_writes_cnt)); - } - - -@@ -457,6 +463,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, - zp->z_blksz = blksz; - zp->z_seq = 0x7A4653; - zp->z_sync_cnt = 0; -+ zp->z_sync_writes_cnt = 0; -+ zp->z_async_writes_cnt = 0; - #if __FreeBSD_version >= 1300139 - atomic_store_ptr(&zp->z_cached_symlink, NULL); - #endif -diff --git a/module/os/linux/spl/spl-cred.c b/module/os/linux/spl/spl-cred.c -index f81b9540a..d407fc66b 100644 ---- a/module/os/linux/spl/spl-cred.c -+++ b/module/os/linux/spl/spl-cred.c -@@ -145,6 +145,18 @@ crgetgid(const cred_t *cr) - return (KGID_TO_SGID(cr->fsgid)); - } - -+/* Return the initial user ns or nop_mnt_idmap */ -+zidmap_t * -+zfs_get_init_idmap(void) -+{ -+#ifdef HAVE_IOPS_CREATE_IDMAP -+ return ((zidmap_t *)&nop_mnt_idmap); -+#else -+ return ((zidmap_t *)&init_user_ns); -+#endif -+} -+ -+EXPORT_SYMBOL(zfs_get_init_idmap); - EXPORT_SYMBOL(crhold); - EXPORT_SYMBOL(crfree); - EXPORT_SYMBOL(crgetuid); -diff --git a/module/os/linux/spl/spl-generic.c b/module/os/linux/spl/spl-generic.c -index 508fb9d4c..2cb5251d7 100644 ---- a/module/os/linux/spl/spl-generic.c -+++ b/module/os/linux/spl/spl-generic.c -@@ -225,8 +225,10 @@ __div_u64(uint64_t u, uint32_t v) - * replacements for libgcc-provided functions and will never be called - * directly. - */ -+#if defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wmissing-prototypes" -+#endif - - /* - * Implementation of 64-bit unsigned division for 32-bit machines. -@@ -425,7 +427,9 @@ __aeabi_ldivmod(int64_t u, int64_t v) - EXPORT_SYMBOL(__aeabi_ldivmod); - #endif /* __arm || __arm__ */ - -+#if defined(__GNUC__) && !defined(__clang__) - #pragma GCC diagnostic pop -+#endif - - #endif /* BITS_PER_LONG */ - -diff --git a/module/os/linux/spl/spl-kmem-cache.c b/module/os/linux/spl/spl-kmem-cache.c -index 5a318e0a5..d586afa9b 100644 ---- a/module/os/linux/spl/spl-kmem-cache.c -+++ b/module/os/linux/spl/spl-kmem-cache.c -@@ -183,8 +183,11 @@ kv_free(spl_kmem_cache_t *skc, void *ptr, int size) - * of that infrastructure we are responsible for incrementing it. - */ - if (current->reclaim_state) -+#ifdef HAVE_RECLAIM_STATE_RECLAIMED -+ current->reclaim_state->reclaimed += size >> PAGE_SHIFT; -+#else - current->reclaim_state->reclaimed_slab += size >> PAGE_SHIFT; -- -+#endif - vfree(ptr); - } - -diff --git a/module/os/linux/zfs/arc_os.c b/module/os/linux/zfs/arc_os.c -index f96cd1271..fc76fe0e0 100644 ---- a/module/os/linux/zfs/arc_os.c -+++ b/module/os/linux/zfs/arc_os.c -@@ -219,7 +219,11 @@ arc_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) - arc_reduce_target_size(ptob(sc->nr_to_scan)); - arc_wait_for_eviction(ptob(sc->nr_to_scan), B_FALSE); - if (current->reclaim_state != NULL) -+#ifdef HAVE_RECLAIM_STATE_RECLAIMED -+ current->reclaim_state->reclaimed += sc->nr_to_scan; -+#else - current->reclaim_state->reclaimed_slab += sc->nr_to_scan; -+#endif - - /* - * We are experiencing memory pressure which the arc_evict_zthr was -diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c -index 5a52092bb..8d508bcb4 100644 ---- a/module/os/linux/zfs/policy.c -+++ b/module/os/linux/zfs/policy.c -@@ -124,7 +124,7 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner) - if (crgetuid(cr) == owner) - return (0); - -- if (zpl_inode_owner_or_capable(kcred->user_ns, ip)) -+ if (zpl_inode_owner_or_capable(zfs_init_idmap, ip)) - return (0); - - #if defined(CONFIG_USER_NS) -diff --git a/module/os/linux/zfs/zfs_ctldir.c b/module/os/linux/zfs/zfs_ctldir.c -index c45644a69..743b03412 100644 ---- a/module/os/linux/zfs/zfs_ctldir.c -+++ b/module/os/linux/zfs/zfs_ctldir.c -@@ -468,7 +468,9 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id, - zp->z_atime_dirty = B_FALSE; - zp->z_zn_prefetch = B_FALSE; - zp->z_is_sa = B_FALSE; -+#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE) - zp->z_is_mapped = B_FALSE; -+#endif - zp->z_is_ctldir = B_TRUE; - zp->z_sa_hdl = NULL; - zp->z_blksz = 0; -@@ -478,6 +480,8 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id, - zp->z_pflags = 0; - zp->z_mode = 0; - zp->z_sync_cnt = 0; -+ zp->z_sync_writes_cnt = 0; -+ zp->z_async_writes_cnt = 0; - ip->i_generation = 0; - ip->i_ino = id; - ip->i_mode = (S_IFDIR | S_IRWXUGO); -diff --git a/module/os/linux/zfs/zfs_ioctl_os.c b/module/os/linux/zfs/zfs_ioctl_os.c -index 79b9d777d..767d3a377 100644 ---- a/module/os/linux/zfs/zfs_ioctl_os.c -+++ b/module/os/linux/zfs/zfs_ioctl_os.c -@@ -288,6 +288,8 @@ zfsdev_detach(void) - #define ZFS_DEBUG_STR "" - #endif - -+zidmap_t *zfs_init_idmap; -+ - static int __init - openzfs_init(void) - { -@@ -311,6 +313,8 @@ openzfs_init(void) - printk(KERN_NOTICE "ZFS: Posix ACLs disabled by kernel\n"); - #endif /* CONFIG_FS_POSIX_ACL */ - -+ zfs_init_idmap = (zidmap_t *)zfs_get_init_idmap(); -+ - return (0); - } - -diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c -index da897f120..e620eb43a 100644 ---- a/module/os/linux/zfs/zfs_vfsops.c -+++ b/module/os/linux/zfs/zfs_vfsops.c -@@ -1192,7 +1192,7 @@ zfs_prune_aliases(zfsvfs_t *zfsvfs, unsigned long nr_to_scan) - int objects = 0; - int i = 0, j = 0; - -- zp_array = kmem_zalloc(max_array * sizeof (znode_t *), KM_SLEEP); -+ zp_array = vmem_zalloc(max_array * sizeof (znode_t *), KM_SLEEP); - - mutex_enter(&zfsvfs->z_znodes_lock); - while ((zp = list_head(&zfsvfs->z_all_znodes)) != NULL) { -@@ -1228,7 +1228,7 @@ zfs_prune_aliases(zfsvfs_t *zfsvfs, unsigned long nr_to_scan) - zrele(zp); - } - -- kmem_free(zp_array, max_array * sizeof (znode_t *)); -+ vmem_free(zp_array, max_array * sizeof (znode_t *)); - - return (objects); - } -diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c -index ae0401e60..af0d553d5 100644 ---- a/module/os/linux/zfs/zfs_vnops_os.c -+++ b/module/os/linux/zfs/zfs_vnops_os.c -@@ -244,43 +244,46 @@ zfs_close(struct inode *ip, int flag, cred_t *cr) - } - - #if defined(_KERNEL) -+ -+static int zfs_fillpage(struct inode *ip, struct page *pp); -+ - /* - * When a file is memory mapped, we must keep the IO data synchronized -- * between the DMU cache and the memory mapped pages. What this means: -- * -- * On Write: If we find a memory mapped page, we write to *both* -- * the page and the dmu buffer. -+ * between the DMU cache and the memory mapped pages. Update all mapped -+ * pages with the contents of the coresponding dmu buffer. - */ - void - update_pages(znode_t *zp, int64_t start, int len, objset_t *os) - { -- struct inode *ip = ZTOI(zp); -- struct address_space *mp = ip->i_mapping; -- struct page *pp; -- uint64_t nbytes; -- int64_t off; -- void *pb; -+ struct address_space *mp = ZTOI(zp)->i_mapping; -+ int64_t off = start & (PAGE_SIZE - 1); - -- off = start & (PAGE_SIZE-1); - for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) { -- nbytes = MIN(PAGE_SIZE - off, len); -+ uint64_t nbytes = MIN(PAGE_SIZE - off, len); - -- pp = find_lock_page(mp, start >> PAGE_SHIFT); -+ struct page *pp = find_lock_page(mp, start >> PAGE_SHIFT); - if (pp) { - if (mapping_writably_mapped(mp)) - flush_dcache_page(pp); - -- pb = kmap(pp); -- (void) dmu_read(os, zp->z_id, start + off, nbytes, -- pb + off, DMU_READ_PREFETCH); -+ void *pb = kmap(pp); -+ int error = dmu_read(os, zp->z_id, start + off, -+ nbytes, pb + off, DMU_READ_PREFETCH); - kunmap(pp); - -- if (mapping_writably_mapped(mp)) -- flush_dcache_page(pp); -+ if (error) { -+ SetPageError(pp); -+ ClearPageUptodate(pp); -+ } else { -+ ClearPageError(pp); -+ SetPageUptodate(pp); -+ -+ if (mapping_writably_mapped(mp)) -+ flush_dcache_page(pp); -+ -+ mark_page_accessed(pp); -+ } - -- mark_page_accessed(pp); -- SetPageUptodate(pp); -- ClearPageError(pp); - unlock_page(pp); - put_page(pp); - } -@@ -291,38 +294,44 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os) - } - - /* -- * When a file is memory mapped, we must keep the IO data synchronized -- * between the DMU cache and the memory mapped pages. What this means: -- * -- * On Read: We "read" preferentially from memory mapped pages, -- * else we default from the dmu buffer. -- * -- * NOTE: We will always "break up" the IO into PAGESIZE uiomoves when -- * the file is memory mapped. -+ * When a file is memory mapped, we must keep the I/O data synchronized -+ * between the DMU cache and the memory mapped pages. Preferentially read -+ * from memory mapped pages, otherwise fallback to reading through the dmu. - */ - int - mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio) - { - struct inode *ip = ZTOI(zp); - struct address_space *mp = ip->i_mapping; -- struct page *pp; -- int64_t start, off; -- uint64_t bytes; -+ int64_t start = uio->uio_loffset; -+ int64_t off = start & (PAGE_SIZE - 1); - int len = nbytes; - int error = 0; -- void *pb; - -- start = uio->uio_loffset; -- off = start & (PAGE_SIZE-1); - for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) { -- bytes = MIN(PAGE_SIZE - off, len); -+ uint64_t bytes = MIN(PAGE_SIZE - off, len); - -- pp = find_lock_page(mp, start >> PAGE_SHIFT); -+ struct page *pp = find_lock_page(mp, start >> PAGE_SHIFT); - if (pp) { -- ASSERT(PageUptodate(pp)); -+ /* -+ * If filemap_fault() retries there exists a window -+ * where the page will be unlocked and not up to date. -+ * In this case we must try and fill the page. -+ */ -+ if (unlikely(!PageUptodate(pp))) { -+ error = zfs_fillpage(ip, pp); -+ if (error) { -+ unlock_page(pp); -+ put_page(pp); -+ return (error); -+ } -+ } -+ -+ ASSERT(PageUptodate(pp) || PageDirty(pp)); -+ - unlock_page(pp); - -- pb = kmap(pp); -+ void *pb = kmap(pp); - error = zfs_uiomove(pb + off, bytes, UIO_READ, uio); - kunmap(pp); - -@@ -338,9 +347,11 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio) - - len -= bytes; - off = 0; -+ - if (error) - break; - } -+ - return (error); - } - #endif /* _KERNEL */ -@@ -1010,7 +1021,7 @@ top: - - mutex_enter(&zp->z_lock); - may_delete_now = atomic_read(&ZTOI(zp)->i_count) == 1 && -- !(zp->z_is_mapped); -+ !zn_has_cached_data(zp, 0, LLONG_MAX); - mutex_exit(&zp->z_lock); - - /* -@@ -1098,7 +1109,8 @@ top: - &xattr_obj_unlinked, sizeof (xattr_obj_unlinked)); - delete_now = may_delete_now && !toobig && - atomic_read(&ZTOI(zp)->i_count) == 1 && -- !(zp->z_is_mapped) && xattr_obj == xattr_obj_unlinked && -+ !zn_has_cached_data(zp, 0, LLONG_MAX) && -+ xattr_obj == xattr_obj_unlinked && - zfs_external_acl(zp) == acl_obj; - } - -@@ -1663,8 +1675,7 @@ out: - */ - /* ARGSUSED */ - int --zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip, -- struct kstat *sp) -+zfs_getattr_fast(zidmap_t *user_ns, struct inode *ip, struct kstat *sp) - { - znode_t *zp = ITOZ(ip); - zfsvfs_t *zfsvfs = ITOZSB(ip); -@@ -3434,21 +3445,34 @@ top: - } - - static void --zfs_putpage_commit_cb(void *arg) -+zfs_putpage_sync_commit_cb(void *arg) -+{ -+ struct page *pp = arg; -+ -+ ClearPageError(pp); -+ end_page_writeback(pp); -+} -+ -+static void -+zfs_putpage_async_commit_cb(void *arg) - { - struct page *pp = arg; -+ znode_t *zp = ITOZ(pp->mapping->host); - - ClearPageError(pp); - end_page_writeback(pp); -+ atomic_dec_32(&zp->z_async_writes_cnt); - } - - /* - * Push a page out to disk, once the page is on stable storage the - * registered commit callback will be run as notification of completion. - * -- * IN: ip - page mapped for inode. -- * pp - page to push (page is locked) -- * wbc - writeback control data -+ * IN: ip - page mapped for inode. -+ * pp - page to push (page is locked) -+ * wbc - writeback control data -+ * for_sync - does the caller intend to wait synchronously for the -+ * page writeback to complete? - * - * RETURN: 0 if success - * error code if failure -@@ -3458,7 +3482,8 @@ zfs_putpage_commit_cb(void *arg) - */ - /* ARGSUSED */ - int --zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) -+zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc, -+ boolean_t for_sync) - { - znode_t *zp = ITOZ(ip); - zfsvfs_t *zfsvfs = ITOZSB(ip); -@@ -3556,6 +3581,16 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) - zfs_rangelock_exit(lr); - - if (wbc->sync_mode != WB_SYNC_NONE) { -+ /* -+ * Speed up any non-sync page writebacks since -+ * they may take several seconds to complete. -+ * Refer to the comment in zpl_fsync() (when -+ * HAVE_FSYNC_RANGE is defined) for details. -+ */ -+ if (atomic_load_32(&zp->z_async_writes_cnt) > 0) { -+ zil_commit(zfsvfs->z_log, zp->z_id); -+ } -+ - if (PageWriteback(pp)) - #ifdef HAVE_PAGEMAP_FOLIO_WAIT_BIT - folio_wait_bit(page_folio(pp), PG_writeback); -@@ -3581,6 +3616,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) - * was in fact not skipped and should not be counted as if it were. - */ - wbc->pages_skipped--; -+ if (!for_sync) -+ atomic_inc_32(&zp->z_async_writes_cnt); - set_page_writeback(pp); - unlock_page(pp); - -@@ -3602,6 +3639,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) - #endif - ClearPageError(pp); - end_page_writeback(pp); -+ if (!for_sync) -+ atomic_dec_32(&zp->z_async_writes_cnt); - zfs_rangelock_exit(lr); - ZFS_EXIT(zfsvfs); - return (err); -@@ -3626,7 +3665,9 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) - err = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx); - - zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, pgoff, pglen, 0, -- zfs_putpage_commit_cb, pp); -+ for_sync ? zfs_putpage_sync_commit_cb : -+ zfs_putpage_async_commit_cb, pp); -+ - dmu_tx_commit(tx); - - zfs_rangelock_exit(lr); -@@ -3638,6 +3679,16 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) - * performance reasons. - */ - zil_commit(zfsvfs->z_log, zp->z_id); -+ } else if (!for_sync && atomic_load_32(&zp->z_sync_writes_cnt) > 0) { -+ /* -+ * If the caller does not intend to wait synchronously -+ * for this page writeback to complete and there are active -+ * synchronous calls on this file, do a commit so that -+ * the latter don't accidentally end up waiting for -+ * our writeback to complete. Refer to the comment in -+ * zpl_fsync() (when HAVE_FSYNC_RANGE is defined) for details. -+ */ -+ zil_commit(zfsvfs->z_log, zp->z_id); - } - - dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, pglen); -@@ -3766,55 +3817,45 @@ zfs_inactive(struct inode *ip) - * Fill pages with data from the disk. - */ - static int --zfs_fillpage(struct inode *ip, struct page *pl[], int nr_pages) -+zfs_fillpage(struct inode *ip, struct page *pp) - { -- znode_t *zp = ITOZ(ip); - zfsvfs_t *zfsvfs = ITOZSB(ip); -- objset_t *os; -- struct page *cur_pp; -- u_offset_t io_off, total; -- size_t io_len; -- loff_t i_size; -- unsigned page_idx; -- int err; -+ loff_t i_size = i_size_read(ip); -+ u_offset_t io_off = page_offset(pp); -+ size_t io_len = PAGE_SIZE; - -- os = zfsvfs->z_os; -- io_len = nr_pages << PAGE_SHIFT; -- i_size = i_size_read(ip); -- io_off = page_offset(pl[0]); -+ ASSERT3U(io_off, <, i_size); - - if (io_off + io_len > i_size) - io_len = i_size - io_off; - -- /* -- * Iterate over list of pages and read each page individually. -- */ -- page_idx = 0; -- for (total = io_off + io_len; io_off < total; io_off += PAGESIZE) { -- caddr_t va; -+ void *va = kmap(pp); -+ int error = dmu_read(zfsvfs->z_os, ITOZ(ip)->z_id, io_off, -+ io_len, va, DMU_READ_PREFETCH); -+ if (io_len != PAGE_SIZE) -+ memset((char *)va + io_len, 0, PAGE_SIZE - io_len); -+ kunmap(pp); - -- cur_pp = pl[page_idx++]; -- va = kmap(cur_pp); -- err = dmu_read(os, zp->z_id, io_off, PAGESIZE, va, -- DMU_READ_PREFETCH); -- kunmap(cur_pp); -- if (err) { -- /* convert checksum errors into IO errors */ -- if (err == ECKSUM) -- err = SET_ERROR(EIO); -- return (err); -- } -+ if (error) { -+ /* convert checksum errors into IO errors */ -+ if (error == ECKSUM) -+ error = SET_ERROR(EIO); -+ -+ SetPageError(pp); -+ ClearPageUptodate(pp); -+ } else { -+ ClearPageError(pp); -+ SetPageUptodate(pp); - } - -- return (0); -+ return (error); - } - - /* -- * Uses zfs_fillpage to read data from the file and fill the pages. -+ * Uses zfs_fillpage to read data from the file and fill the page. - * - * IN: ip - inode of file to get data from. -- * pl - list of pages to read -- * nr_pages - number of pages to read -+ * pp - page to read - * - * RETURN: 0 on success, error code on failure. - * -@@ -3823,24 +3864,22 @@ zfs_fillpage(struct inode *ip, struct page *pl[], int nr_pages) - */ - /* ARGSUSED */ - int --zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages) -+zfs_getpage(struct inode *ip, struct page *pp) - { -- znode_t *zp = ITOZ(ip); - zfsvfs_t *zfsvfs = ITOZSB(ip); -- int err; -- -- if (pl == NULL) -- return (0); -+ znode_t *zp = ITOZ(ip); -+ int error; - - ZFS_ENTER(zfsvfs); - ZFS_VERIFY_ZP(zp); - -- err = zfs_fillpage(ip, pl, nr_pages); -- -- dataset_kstats_update_read_kstats(&zfsvfs->z_kstat, nr_pages*PAGESIZE); -+ error = zfs_fillpage(ip, pp); -+ if (error == 0) -+ dataset_kstats_update_read_kstats(&zfsvfs->z_kstat, PAGE_SIZE); - - ZFS_EXIT(zfsvfs); -- return (err); -+ -+ return (error); - } - - /* -diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c -index f3475b4d9..0236b3216 100644 ---- a/module/os/linux/zfs/zfs_znode.c -+++ b/module/os/linux/zfs/zfs_znode.c -@@ -134,6 +134,9 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) - zp->z_acl_cached = NULL; - zp->z_xattr_cached = NULL; - zp->z_xattr_parent = 0; -+ zp->z_sync_writes_cnt = 0; -+ zp->z_async_writes_cnt = 0; -+ - return (0); - } - -@@ -151,9 +154,12 @@ zfs_znode_cache_destructor(void *buf, void *arg) - rw_destroy(&zp->z_xattr_lock); - zfs_rangelock_fini(&zp->z_rangelock); - -- ASSERT(zp->z_dirlocks == NULL); -- ASSERT(zp->z_acl_cached == NULL); -- ASSERT(zp->z_xattr_cached == NULL); -+ ASSERT3P(zp->z_dirlocks, ==, NULL); -+ ASSERT3P(zp->z_acl_cached, ==, NULL); -+ ASSERT3P(zp->z_xattr_cached, ==, NULL); -+ -+ ASSERT0(atomic_load_32(&zp->z_sync_writes_cnt)); -+ ASSERT0(atomic_load_32(&zp->z_async_writes_cnt)); - } - - static int -@@ -540,7 +546,9 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, - ASSERT3P(zp->z_xattr_cached, ==, NULL); - zp->z_unlinked = B_FALSE; - zp->z_atime_dirty = B_FALSE; -+#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE) - zp->z_is_mapped = B_FALSE; -+#endif - zp->z_is_ctldir = B_FALSE; - zp->z_suspended = B_FALSE; - zp->z_sa_hdl = NULL; -@@ -549,6 +557,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, - zp->z_blksz = blksz; - zp->z_seq = 0x7A4653; - zp->z_sync_cnt = 0; -+ zp->z_sync_writes_cnt = 0; -+ zp->z_async_writes_cnt = 0; - - zfs_znode_sa_init(zfsvfs, zp, db, obj_type, hdl); - -@@ -1628,7 +1638,7 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len) - * Zero partial page cache entries. This must be done under a - * range lock in order to keep the ARC and page cache in sync. - */ -- if (zp->z_is_mapped) { -+ if (zn_has_cached_data(zp, off, off + len - 1)) { - loff_t first_page, last_page, page_len; - loff_t first_page_offset, last_page_offset; - -diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c -index 9b526afd0..cf4da470f 100644 ---- a/module/os/linux/zfs/zpl_ctldir.c -+++ b/module/os/linux/zfs/zpl_ctldir.c -@@ -101,7 +101,11 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir) - */ - /* ARGSUSED */ - static int --#ifdef HAVE_USERNS_IOPS_GETATTR -+#ifdef HAVE_IDMAP_IOPS_GETATTR -+zpl_root_getattr_impl(struct mnt_idmap *user_ns, -+ const struct path *path, struct kstat *stat, u32 request_mask, -+ unsigned int query_flags) -+#elif defined(HAVE_USERNS_IOPS_GETATTR) - zpl_root_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) -@@ -112,8 +116,14 @@ zpl_root_getattr_impl(const struct path *path, struct kstat *stat, - { - struct inode *ip = path->dentry->d_inode; - --#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) -+#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) -+#ifdef HAVE_GENERIC_FILLATTR_USERNS - generic_fillattr(user_ns, ip, stat); -+#elif defined(HAVE_GENERIC_FILLATTR_IDMAP) -+ generic_fillattr(user_ns, ip, stat); -+#else -+ (void) user_ns; -+#endif - #else - generic_fillattr(ip, stat); - #endif -@@ -304,6 +314,10 @@ static int - zpl_snapdir_rename2(struct user_namespace *user_ns, struct inode *sdip, - struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, - unsigned int flags) -+#elif defined(HAVE_IOPS_RENAME_IDMAP) -+zpl_snapdir_rename2(struct mnt_idmap *user_ns, struct inode *sdip, -+ struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, -+ unsigned int flags) - #else - zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry, - struct inode *tdip, struct dentry *tdentry, unsigned int flags) -@@ -325,7 +339,9 @@ zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry, - return (error); - } - --#if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS) -+#if (!defined(HAVE_RENAME_WANTS_FLAGS) && \ -+ !defined(HAVE_IOPS_RENAME_USERNS) && \ -+ !defined(HAVE_IOPS_RENAME_IDMAP)) - static int - zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry, - struct inode *tdip, struct dentry *tdentry) -@@ -352,6 +368,9 @@ static int - #ifdef HAVE_IOPS_MKDIR_USERNS - zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip, - struct dentry *dentry, umode_t mode) -+#elif defined(HAVE_IOPS_MKDIR_IDMAP) -+zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip, -+ struct dentry *dentry, umode_t mode) - #else - zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) - #endif -@@ -384,7 +403,11 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) - */ - /* ARGSUSED */ - static int --#ifdef HAVE_USERNS_IOPS_GETATTR -+#ifdef HAVE_IDMAP_IOPS_GETATTR -+zpl_snapdir_getattr_impl(struct mnt_idmap *user_ns, -+ const struct path *path, struct kstat *stat, u32 request_mask, -+ unsigned int query_flags) -+#elif defined(HAVE_USERNS_IOPS_GETATTR) - zpl_snapdir_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) -@@ -397,8 +420,14 @@ zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat, - zfsvfs_t *zfsvfs = ITOZSB(ip); - - ZPL_ENTER(zfsvfs); --#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) -+#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) -+#ifdef HAVE_GENERIC_FILLATTR_USERNS -+ generic_fillattr(user_ns, ip, stat); -+#elif defined(HAVE_GENERIC_FILLATTR_IDMAP) - generic_fillattr(user_ns, ip, stat); -+#else -+ (void) user_ns; -+#endif - #else - generic_fillattr(ip, stat); - #endif -@@ -439,7 +468,9 @@ const struct file_operations zpl_fops_snapdir = { - const struct inode_operations zpl_ops_snapdir = { - .lookup = zpl_snapdir_lookup, - .getattr = zpl_snapdir_getattr, --#if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) -+#if (defined(HAVE_RENAME_WANTS_FLAGS) || \ -+ defined(HAVE_IOPS_RENAME_USERNS) || \ -+ defined(HAVE_IOPS_RENAME_IDMAP)) - .rename = zpl_snapdir_rename2, - #else - .rename = zpl_snapdir_rename, -@@ -530,6 +561,10 @@ static int - zpl_shares_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) -+#elif defined(HAVE_IDMAP_IOPS_GETATTR) -+zpl_shares_getattr_impl(struct mnt_idmap *user_ns, -+ const struct path *path, struct kstat *stat, u32 request_mask, -+ unsigned int query_flags) - #else - zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int query_flags) -@@ -543,8 +578,14 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, - ZPL_ENTER(zfsvfs); - - if (zfsvfs->z_shares_dir == 0) { --#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) -+#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) -+#ifdef HAVE_GENERIC_FILLATTR_USERNS -+ generic_fillattr(user_ns, path->dentry->d_inode, stat); -+#elif defined(HAVE_GENERIC_FILLATTR_IDMAP) - generic_fillattr(user_ns, path->dentry->d_inode, stat); -+#else -+ (void) user_ns; -+#endif - #else - generic_fillattr(path->dentry->d_inode, stat); - #endif -@@ -556,7 +597,7 @@ zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, - - error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); - if (error == 0) { --#if defined(HAVE_GENERIC_FILLATTR_USERNS) && defined(HAVE_USERNS_IOPS_GETATTR) -+#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) - error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat); - #else - error = -zfs_getattr_fast(kcred->user_ns, ZTOI(dzp), stat); -diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c -index 38d2bd147..d5d354db1 100644 ---- a/module/os/linux/zfs/zpl_file.c -+++ b/module/os/linux/zfs/zpl_file.c -@@ -165,17 +165,56 @@ static int - zpl_fsync(struct file *filp, loff_t start, loff_t end, int datasync) - { - struct inode *inode = filp->f_mapping->host; -+ znode_t *zp = ITOZ(inode); -+ zfsvfs_t *zfsvfs = ITOZSB(inode); - cred_t *cr = CRED(); - int error; - fstrans_cookie_t cookie; - -+ /* -+ * The variables z_sync_writes_cnt and z_async_writes_cnt work in -+ * tandem so that sync writes can detect if there are any non-sync -+ * writes going on and vice-versa. The "vice-versa" part to this logic -+ * is located in zfs_putpage() where non-sync writes check if there are -+ * any ongoing sync writes. If any sync and non-sync writes overlap, -+ * we do a commit to complete the non-sync writes since the latter can -+ * potentially take several seconds to complete and thus block sync -+ * writes in the upcoming call to filemap_write_and_wait_range(). -+ */ -+ atomic_inc_32(&zp->z_sync_writes_cnt); -+ /* -+ * If the following check does not detect an overlapping non-sync write -+ * (say because it's just about to start), then it is guaranteed that -+ * the non-sync write will detect this sync write. This is because we -+ * always increment z_sync_writes_cnt / z_async_writes_cnt before doing -+ * the check on z_async_writes_cnt / z_sync_writes_cnt here and in -+ * zfs_putpage() respectively. -+ */ -+ if (atomic_load_32(&zp->z_async_writes_cnt) > 0) { -+ ZPL_ENTER(zfsvfs); -+ zil_commit(zfsvfs->z_log, zp->z_id); -+ ZPL_EXIT(zfsvfs); -+ } -+ - error = filemap_write_and_wait_range(inode->i_mapping, start, end); -+ -+ /* -+ * The sync write is not complete yet but we decrement -+ * z_sync_writes_cnt since zfs_fsync() increments and decrements -+ * it internally. If a non-sync write starts just after the decrement -+ * operation but before we call zfs_fsync(), it may not detect this -+ * overlapping sync write but it does not matter since we have already -+ * gone past filemap_write_and_wait_range() and we won't block due to -+ * the non-sync write. -+ */ -+ atomic_dec_32(&zp->z_sync_writes_cnt); -+ - if (error) - return (error); - - crhold(cr); - cookie = spl_fstrans_mark(); -- error = -zfs_fsync(ITOZ(inode), datasync, cr); -+ error = -zfs_fsync(zp, datasync, cr); - spl_fstrans_unmark(cookie); - crfree(cr); - ASSERT3S(error, <=, 0); -@@ -579,7 +618,6 @@ static int - zpl_mmap(struct file *filp, struct vm_area_struct *vma) - { - struct inode *ip = filp->f_mapping->host; -- znode_t *zp = ITOZ(ip); - int error; - fstrans_cookie_t cookie; - -@@ -594,9 +632,12 @@ zpl_mmap(struct file *filp, struct vm_area_struct *vma) - if (error) - return (error); - -+#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE) -+ znode_t *zp = ITOZ(ip); - mutex_enter(&zp->z_lock); - zp->z_is_mapped = B_TRUE; - mutex_exit(&zp->z_lock); -+#endif - - return (error); - } -@@ -609,29 +650,16 @@ zpl_mmap(struct file *filp, struct vm_area_struct *vma) - static inline int - zpl_readpage_common(struct page *pp) - { -- struct inode *ip; -- struct page *pl[1]; -- int error = 0; - fstrans_cookie_t cookie; - - ASSERT(PageLocked(pp)); -- ip = pp->mapping->host; -- pl[0] = pp; - - cookie = spl_fstrans_mark(); -- error = -zfs_getpage(ip, pl, 1); -+ int error = -zfs_getpage(pp->mapping->host, pp); - spl_fstrans_unmark(cookie); - -- if (error) { -- SetPageError(pp); -- ClearPageUptodate(pp); -- } else { -- ClearPageError(pp); -- SetPageUptodate(pp); -- flush_dcache_page(pp); -- } -- - unlock_page(pp); -+ - return (error); - } - -@@ -688,19 +716,42 @@ zpl_readahead(struct readahead_control *ractl) - static int - zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data) - { -- struct address_space *mapping = data; -+ boolean_t *for_sync = data; - fstrans_cookie_t cookie; - - ASSERT(PageLocked(pp)); - ASSERT(!PageWriteback(pp)); - - cookie = spl_fstrans_mark(); -- (void) zfs_putpage(mapping->host, pp, wbc); -+ (void) zfs_putpage(pp->mapping->host, pp, wbc, *for_sync); - spl_fstrans_unmark(cookie); - - return (0); - } - -+#ifdef HAVE_WRITEPAGE_T_FOLIO -+static int -+zpl_putfolio(struct folio *pp, struct writeback_control *wbc, void *data) -+{ -+ (void) zpl_putpage(&pp->page, wbc, data); -+ return (0); -+} -+#endif -+ -+static inline int -+zpl_write_cache_pages(struct address_space *mapping, -+ struct writeback_control *wbc, void *data) -+{ -+ int result; -+ -+#ifdef HAVE_WRITEPAGE_T_FOLIO -+ result = write_cache_pages(mapping, wbc, zpl_putfolio, data); -+#else -+ result = write_cache_pages(mapping, wbc, zpl_putpage, data); -+#endif -+ return (result); -+} -+ - static int - zpl_writepages(struct address_space *mapping, struct writeback_control *wbc) - { -@@ -722,8 +773,9 @@ zpl_writepages(struct address_space *mapping, struct writeback_control *wbc) - * we run it once in non-SYNC mode so that the ZIL gets all the data, - * and then we commit it all in one go. - */ -+ boolean_t for_sync = (sync_mode == WB_SYNC_ALL); - wbc->sync_mode = WB_SYNC_NONE; -- result = write_cache_pages(mapping, wbc, zpl_putpage, mapping); -+ result = zpl_write_cache_pages(mapping, wbc, &for_sync); - if (sync_mode != wbc->sync_mode) { - ZPL_ENTER(zfsvfs); - ZPL_VERIFY_ZP(zp); -@@ -739,7 +791,7 @@ zpl_writepages(struct address_space *mapping, struct writeback_control *wbc) - * details). That being said, this is a no-op in most cases. - */ - wbc->sync_mode = sync_mode; -- result = write_cache_pages(mapping, wbc, zpl_putpage, mapping); -+ result = zpl_write_cache_pages(mapping, wbc, &for_sync); - } - return (result); - } -@@ -756,7 +808,9 @@ zpl_writepage(struct page *pp, struct writeback_control *wbc) - if (ITOZSB(pp->mapping->host)->z_os->os_sync == ZFS_SYNC_ALWAYS) - wbc->sync_mode = WB_SYNC_ALL; - -- return (zpl_putpage(pp, wbc, pp->mapping)); -+ boolean_t for_sync = (wbc->sync_mode == WB_SYNC_ALL); -+ -+ return (zpl_putpage(pp, wbc, &for_sync)); - } - - /* -@@ -924,7 +978,7 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva) - !capable(CAP_LINUX_IMMUTABLE)) - return (-EPERM); - -- if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) -+ if (!zpl_inode_owner_or_capable(zfs_init_idmap, ip)) - return (-EACCES); - - xva_init(xva); -diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c -index dd634f70e..6efaaf438 100644 ---- a/module/os/linux/zfs/zpl_inode.c -+++ b/module/os/linux/zfs/zpl_inode.c -@@ -131,6 +131,9 @@ static int - #ifdef HAVE_IOPS_CREATE_USERNS - zpl_create(struct user_namespace *user_ns, struct inode *dir, - struct dentry *dentry, umode_t mode, bool flag) -+#elif defined(HAVE_IOPS_CREATE_IDMAP) -+zpl_create(struct mnt_idmap *user_ns, struct inode *dir, -+ struct dentry *dentry, umode_t mode, bool flag) - #else - zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag) - #endif -@@ -174,6 +177,9 @@ static int - #ifdef HAVE_IOPS_MKNOD_USERNS - zpl_mknod(struct user_namespace *user_ns, struct inode *dir, - struct dentry *dentry, umode_t mode, -+#elif defined(HAVE_IOPS_MKNOD_IDMAP) -+zpl_mknod(struct mnt_idmap *user_ns, struct inode *dir, -+ struct dentry *dentry, umode_t mode, - #else - zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, - #endif -@@ -224,7 +230,10 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, - - #ifdef HAVE_TMPFILE - static int --#ifndef HAVE_TMPFILE_DENTRY -+#ifdef HAVE_TMPFILE_IDMAP -+zpl_tmpfile(struct mnt_idmap *userns, struct inode *dir, -+ struct file *file, umode_t mode) -+#elif !defined(HAVE_TMPFILE_DENTRY) - zpl_tmpfile(struct user_namespace *userns, struct inode *dir, - struct file *file, umode_t mode) - #else -@@ -317,6 +326,9 @@ static int - #ifdef HAVE_IOPS_MKDIR_USERNS - zpl_mkdir(struct user_namespace *user_ns, struct inode *dir, - struct dentry *dentry, umode_t mode) -+#elif defined(HAVE_IOPS_MKDIR_IDMAP) -+zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir, -+ struct dentry *dentry, umode_t mode) - #else - zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) - #endif -@@ -386,6 +398,10 @@ static int - zpl_getattr_impl(struct user_namespace *user_ns, - const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) -+#elif defined(HAVE_IDMAP_IOPS_GETATTR) -+zpl_getattr_impl(struct mnt_idmap *user_ns, -+ const struct path *path, struct kstat *stat, u32 request_mask, -+ unsigned int query_flags) - #else - zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, - unsigned int query_flags) -@@ -402,7 +418,7 @@ zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, - * XXX query_flags currently ignored. - */ - --#ifdef HAVE_USERNS_IOPS_GETATTR -+#if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) - error = -zfs_getattr_fast(user_ns, ip, stat); - #else - error = -zfs_getattr_fast(kcred->user_ns, ip, stat); -@@ -441,9 +457,12 @@ zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask, - ZPL_GETATTR_WRAPPER(zpl_getattr); - - static int --#ifdef HAVE_SETATTR_PREPARE_USERNS -+#ifdef HAVE_USERNS_IOPS_SETATTR - zpl_setattr(struct user_namespace *user_ns, struct dentry *dentry, - struct iattr *ia) -+#elif defined(HAVE_IDMAP_IOPS_SETATTR) -+zpl_setattr(struct mnt_idmap *user_ns, struct dentry *dentry, -+ struct iattr *ia) - #else - zpl_setattr(struct dentry *dentry, struct iattr *ia) - #endif -@@ -454,7 +473,13 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) - int error; - fstrans_cookie_t cookie; - -- error = zpl_setattr_prepare(kcred->user_ns, dentry, ia); -+#ifdef HAVE_SETATTR_PREPARE_USERNS -+ error = zpl_setattr_prepare(user_ns, dentry, ia); -+#elif defined(HAVE_SETATTR_PREPARE_IDMAP) -+ error = zpl_setattr_prepare(user_ns, dentry, ia); -+#else -+ error = zpl_setattr_prepare(zfs_init_idmap, dentry, ia); -+#endif - if (error) - return (error); - -@@ -489,10 +514,14 @@ static int - #ifdef HAVE_IOPS_RENAME_USERNS - zpl_rename2(struct user_namespace *user_ns, struct inode *sdip, - struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, -- unsigned int flags) -+ unsigned int rflags) -+#elif defined(HAVE_IOPS_RENAME_IDMAP) -+zpl_rename2(struct mnt_idmap *user_ns, struct inode *sdip, -+ struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, -+ unsigned int rflags) - #else - zpl_rename2(struct inode *sdip, struct dentry *sdentry, -- struct inode *tdip, struct dentry *tdentry, unsigned int flags) -+ struct inode *tdip, struct dentry *tdentry, unsigned int rflags) - #endif - { - cred_t *cr = CRED(); -@@ -500,7 +529,7 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry, - fstrans_cookie_t cookie; - - /* We don't have renameat2(2) support */ -- if (flags) -+ if (rflags) - return (-EINVAL); - - crhold(cr); -@@ -514,7 +543,9 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry, - return (error); - } - --#if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS) -+#if !defined(HAVE_IOPS_RENAME_USERNS) && \ -+ !defined(HAVE_RENAME_WANTS_FLAGS) && \ -+ !defined(HAVE_IOPS_RENAME_IDMAP) - static int - zpl_rename(struct inode *sdip, struct dentry *sdentry, - struct inode *tdip, struct dentry *tdentry) -@@ -527,6 +558,9 @@ static int - #ifdef HAVE_IOPS_SYMLINK_USERNS - zpl_symlink(struct user_namespace *user_ns, struct inode *dir, - struct dentry *dentry, const char *name) -+#elif defined(HAVE_IOPS_SYMLINK_IDMAP) -+zpl_symlink(struct mnt_idmap *user_ns, struct inode *dir, -+ struct dentry *dentry, const char *name) - #else - zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) - #endif -@@ -745,6 +779,8 @@ const struct inode_operations zpl_dir_inode_operations = { - .mknod = zpl_mknod, - #if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) - .rename = zpl_rename2, -+#elif defined(HAVE_IOPS_RENAME_IDMAP) -+ .rename = zpl_rename2, - #else - .rename = zpl_rename, - #endif -diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c -index 364cd34c1..084817609 100644 ---- a/module/os/linux/zfs/zpl_xattr.c -+++ b/module/os/linux/zfs/zpl_xattr.c -@@ -725,9 +725,11 @@ __zpl_xattr_user_get(struct inode *ip, const char *name, - ZPL_XATTR_GET_WRAPPER(zpl_xattr_user_get); - - static int --__zpl_xattr_user_set(struct inode *ip, const char *name, -+__zpl_xattr_user_set(zidmap_t *user_ns, -+ struct inode *ip, const char *name, - const void *value, size_t size, int flags) - { -+ (void) user_ns; - char *xattr_name; - int error; - /* xattr_resolve_name will do this for us if this is defined */ -@@ -794,9 +796,11 @@ __zpl_xattr_trusted_get(struct inode *ip, const char *name, - ZPL_XATTR_GET_WRAPPER(zpl_xattr_trusted_get); - - static int --__zpl_xattr_trusted_set(struct inode *ip, const char *name, -+__zpl_xattr_trusted_set(zidmap_t *user_ns, -+ struct inode *ip, const char *name, - const void *value, size_t size, int flags) - { -+ (void) user_ns; - char *xattr_name; - int error; - -@@ -863,9 +867,11 @@ __zpl_xattr_security_get(struct inode *ip, const char *name, - ZPL_XATTR_GET_WRAPPER(zpl_xattr_security_get); - - static int --__zpl_xattr_security_set(struct inode *ip, const char *name, -+__zpl_xattr_security_set(zidmap_t *user_ns, -+ struct inode *ip, const char *name, - const void *value, size_t size, int flags) - { -+ (void) user_ns; - char *xattr_name; - int error; - /* xattr_resolve_name will do this for us if this is defined */ -@@ -889,7 +895,7 @@ zpl_xattr_security_init_impl(struct inode *ip, const struct xattr *xattrs, - int error = 0; - - for (xattr = xattrs; xattr->name != NULL; xattr++) { -- error = __zpl_xattr_security_set(ip, -+ error = __zpl_xattr_security_set(NULL, ip, - xattr->name, xattr->value, xattr->value_len, 0); - - if (error < 0) -@@ -1004,6 +1010,9 @@ int - #ifdef HAVE_SET_ACL_USERNS - zpl_set_acl(struct user_namespace *userns, struct inode *ip, - struct posix_acl *acl, int type) -+#elif defined(HAVE_SET_ACL_IDMAP_DENTRY) -+zpl_set_acl(struct mnt_idmap *userns, struct dentry *dentry, -+ struct posix_acl *acl, int type) - #elif defined(HAVE_SET_ACL_USERNS_DENTRY_ARG2) - zpl_set_acl(struct user_namespace *userns, struct dentry *dentry, - struct posix_acl *acl, int type) -@@ -1013,6 +1022,8 @@ zpl_set_acl(struct inode *ip, struct posix_acl *acl, int type) - { - #ifdef HAVE_SET_ACL_USERNS_DENTRY_ARG2 - return (zpl_set_acl_impl(d_inode(dentry), acl, type)); -+#elif defined(HAVE_SET_ACL_IDMAP_DENTRY) -+ return (zpl_set_acl_impl(d_inode(dentry), acl, type)); - #else - return (zpl_set_acl_impl(ip, acl, type)); - #endif /* HAVE_SET_ACL_USERNS_DENTRY_ARG2 */ -@@ -1256,7 +1267,8 @@ __zpl_xattr_acl_get_default(struct inode *ip, const char *name, - ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_default); - - static int --__zpl_xattr_acl_set_access(struct inode *ip, const char *name, -+__zpl_xattr_acl_set_access(zidmap_t *mnt_ns, -+ struct inode *ip, const char *name, - const void *value, size_t size, int flags) - { - struct posix_acl *acl; -@@ -1270,8 +1282,14 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name, - if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) - return (-EOPNOTSUPP); - -- if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) -+#if defined(HAVE_XATTR_SET_USERNS) || defined(HAVE_XATTR_SET_IDMAP) -+ if (!zpl_inode_owner_or_capable(mnt_ns, ip)) -+ return (-EPERM); -+#else -+ (void) mnt_ns; -+ if (!zpl_inode_owner_or_capable(zfs_init_idmap, ip)) - return (-EPERM); -+#endif - - if (value) { - acl = zpl_acl_from_xattr(value, size); -@@ -1295,7 +1313,8 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name, - ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_access); - - static int --__zpl_xattr_acl_set_default(struct inode *ip, const char *name, -+__zpl_xattr_acl_set_default(zidmap_t *mnt_ns, -+ struct inode *ip, const char *name, - const void *value, size_t size, int flags) - { - struct posix_acl *acl; -@@ -1309,8 +1328,14 @@ __zpl_xattr_acl_set_default(struct inode *ip, const char *name, - if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) - return (-EOPNOTSUPP); - -- if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) -+#if defined(HAVE_XATTR_SET_USERNS) || defined(HAVE_XATTR_SET_IDMAP) -+ if (!zpl_inode_owner_or_capable(mnt_ns, ip)) -+ return (-EPERM); -+#else -+ (void) mnt_ns; -+ if (!zpl_inode_owner_or_capable(zfs_init_idmap, ip)) - return (-EPERM); -+#endif - - if (value) { - acl = zpl_acl_from_xattr(value, size); -diff --git a/module/zcommon/Makefile.in b/module/zcommon/Makefile.in -index ebc538440..614968a42 100644 ---- a/module/zcommon/Makefile.in -+++ b/module/zcommon/Makefile.in -@@ -26,3 +26,7 @@ $(MODULE)-$(CONFIG_X86) += zfs_fletcher_intel.o - $(MODULE)-$(CONFIG_X86) += zfs_fletcher_sse.o - $(MODULE)-$(CONFIG_X86) += zfs_fletcher_avx512.o - $(MODULE)-$(CONFIG_ARM64) += zfs_fletcher_aarch64_neon.o -+ -+ifeq ($(CONFIG_ARM64),y) -+CFLAGS_REMOVE_zfs_fletcher_aarch64_neon.o += -mgeneral-regs-only -+endif -diff --git a/module/zfs/Makefile.in b/module/zfs/Makefile.in -index 653ea0da9..0e04d7ef0 100644 ---- a/module/zfs/Makefile.in -+++ b/module/zfs/Makefile.in -@@ -154,4 +154,9 @@ ifeq ($(CONFIG_ALTIVEC),y) - $(obj)/vdev_raidz_math_powerpc_altivec.o: c_flags += -maltivec - endif - -+ifeq ($(CONFIG_ARM64),y) -+CFLAGS_REMOVE_vdev_raidz_math_aarch64_neon.o += -mgeneral-regs-only -+CFLAGS_REMOVE_vdev_raidz_math_aarch64_neonx2.o += -mgeneral-regs-only -+endif -+ - include $(mfdir)/../os/linux/zfs/Makefile -diff --git a/module/zfs/abd.c b/module/zfs/abd.c -index 8ee8e7e57..754974a55 100644 ---- a/module/zfs/abd.c -+++ b/module/zfs/abd.c -@@ -109,7 +109,6 @@ void - abd_verify(abd_t *abd) - { - #ifdef ZFS_DEBUG -- ASSERT3U(abd->abd_size, >, 0); - ASSERT3U(abd->abd_size, <=, SPA_MAXBLOCKSIZE); - ASSERT3U(abd->abd_flags, ==, abd->abd_flags & (ABD_FLAG_LINEAR | - ABD_FLAG_OWNER | ABD_FLAG_META | ABD_FLAG_MULTI_ZONE | -@@ -118,6 +117,7 @@ abd_verify(abd_t *abd) - IMPLY(abd->abd_parent != NULL, !(abd->abd_flags & ABD_FLAG_OWNER)); - IMPLY(abd->abd_flags & ABD_FLAG_META, abd->abd_flags & ABD_FLAG_OWNER); - if (abd_is_linear(abd)) { -+ ASSERT3U(abd->abd_size, >, 0); - ASSERT3P(ABD_LINEAR_BUF(abd), !=, NULL); - } else if (abd_is_gang(abd)) { - uint_t child_sizes = 0; -@@ -130,6 +130,7 @@ abd_verify(abd_t *abd) - } - ASSERT3U(abd->abd_size, ==, child_sizes); - } else { -+ ASSERT3U(abd->abd_size, >, 0); - abd_verify_scatter(abd); - } - #endif -@@ -369,7 +370,20 @@ abd_gang_add_gang(abd_t *pabd, abd_t *cabd, boolean_t free_on_free) - * will retain all the free_on_free settings after being - * added to the parents list. - */ -+#ifdef ZFS_DEBUG -+ /* -+ * If cabd had abd_parent, we have to drop it here. We can't -+ * transfer it to pabd, nor we can clear abd_size leaving it. -+ */ -+ if (cabd->abd_parent != NULL) { -+ (void) zfs_refcount_remove_many( -+ &cabd->abd_parent->abd_children, -+ cabd->abd_size, cabd); -+ cabd->abd_parent = NULL; -+ } -+#endif - pabd->abd_size += cabd->abd_size; -+ cabd->abd_size = 0; - list_move_tail(&ABD_GANG(pabd).abd_gang_chain, - &ABD_GANG(cabd).abd_gang_chain); - ASSERT(list_is_empty(&ABD_GANG(cabd).abd_gang_chain)); -@@ -407,7 +421,6 @@ abd_gang_add(abd_t *pabd, abd_t *cabd, boolean_t free_on_free) - */ - if (abd_is_gang(cabd)) { - ASSERT(!list_link_active(&cabd->abd_gang_link)); -- ASSERT(!list_is_empty(&ABD_GANG(cabd).abd_gang_chain)); - return (abd_gang_add_gang(pabd, cabd, free_on_free)); - } - ASSERT(!abd_is_gang(cabd)); -diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c -index 98ca2b3bc..b8161f710 100644 ---- a/module/zfs/dmu_recv.c -+++ b/module/zfs/dmu_recv.c -@@ -71,6 +71,12 @@ int zfs_recv_write_batch_size = 1024 * 1024; - static char *dmu_recv_tag = "dmu_recv_tag"; - const char *recv_clone_name = "%recv"; - -+typedef enum { -+ ORNS_NO, -+ ORNS_YES, -+ ORNS_MAYBE -+} or_need_sync_t; -+ - static int receive_read_payload_and_next_header(dmu_recv_cookie_t *ra, int len, - void *buf); - -@@ -121,6 +127,9 @@ struct receive_writer_arg { - uint8_t or_iv[ZIO_DATA_IV_LEN]; - uint8_t or_mac[ZIO_DATA_MAC_LEN]; - boolean_t or_byteorder; -+ -+ /* Keep track of DRR_FREEOBJECTS right after DRR_OBJECT_RANGE */ -+ or_need_sync_t or_need_sync; - }; - - typedef struct dmu_recv_begin_arg { -@@ -1658,10 +1667,22 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, - /* object was freed and we are about to allocate a new one */ - object_to_hold = DMU_NEW_OBJECT; - } else { -+ /* -+ * If the only record in this range so far was DRR_FREEOBJECTS -+ * with at least one actually freed object, it's possible that -+ * the block will now be converted to a hole. We need to wait -+ * for the txg to sync to prevent races. -+ */ -+ if (rwa->or_need_sync == ORNS_YES) -+ txg_wait_synced(dmu_objset_pool(rwa->os), 0); -+ - /* object is free and we are about to allocate a new one */ - object_to_hold = DMU_NEW_OBJECT; - } - -+ /* Only relevant for the first object in the range */ -+ rwa->or_need_sync = ORNS_NO; -+ - /* - * If this is a multi-slot dnode there is a chance that this - * object will expand into a slot that is already used by -@@ -1856,6 +1877,9 @@ receive_freeobjects(struct receive_writer_arg *rwa, - - if (err != 0) - return (err); -+ -+ if (rwa->or_need_sync == ORNS_MAYBE) -+ rwa->or_need_sync = ORNS_YES; - } - if (next_err != ESRCH) - return (next_err); -@@ -2298,6 +2322,8 @@ receive_object_range(struct receive_writer_arg *rwa, - bcopy(drror->drr_mac, rwa->or_mac, ZIO_DATA_MAC_LEN); - rwa->or_byteorder = byteorder; - -+ rwa->or_need_sync = ORNS_MAYBE; -+ - return (0); - } - -diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c -index cd9ecc07f..0dd1ec210 100644 ---- a/module/zfs/dmu_send.c -+++ b/module/zfs/dmu_send.c -@@ -2797,6 +2797,7 @@ dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok, - } - - if (err == 0) { -+ owned = B_TRUE; - err = zap_lookup(dspp.dp->dp_meta_objset, - dspp.to_ds->ds_object, - DS_FIELD_RESUME_TOGUID, 8, 1, -@@ -2810,21 +2811,24 @@ dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok, - sizeof (dspp.saved_toname), - dspp.saved_toname); - } -- if (err != 0) -+ /* Only disown if there was an error in the lookups */ -+ if (owned && (err != 0)) - dsl_dataset_disown(dspp.to_ds, dsflags, FTAG); - - kmem_strfree(name); - } else { - err = dsl_dataset_own(dspp.dp, tosnap, dsflags, - FTAG, &dspp.to_ds); -+ if (err == 0) -+ owned = B_TRUE; - } -- owned = B_TRUE; - } else { - err = dsl_dataset_hold_flags(dspp.dp, tosnap, dsflags, FTAG, - &dspp.to_ds); - } - - if (err != 0) { -+ /* Note: dsl dataset is not owned at this point */ - dsl_pool_rele(dspp.dp, FTAG); - return (err); - } -diff --git a/module/zfs/dmu_tx.c b/module/zfs/dmu_tx.c -index 1eed0526b..063934f39 100644 ---- a/module/zfs/dmu_tx.c -+++ b/module/zfs/dmu_tx.c -@@ -290,6 +290,53 @@ dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len) - } - } - -+static void -+dmu_tx_count_append(dmu_tx_hold_t *txh, uint64_t off, uint64_t len) -+{ -+ dnode_t *dn = txh->txh_dnode; -+ int err = 0; -+ -+ if (len == 0) -+ return; -+ -+ (void) zfs_refcount_add_many(&txh->txh_space_towrite, len, FTAG); -+ -+ if (dn == NULL) -+ return; -+ -+ /* -+ * For i/o error checking, read the blocks that will be needed -+ * to perform the append; first level-0 block (if not aligned, i.e. -+ * if they are partial-block writes), no additional blocks are read. -+ */ -+ if (dn->dn_maxblkid == 0) { -+ if (off < dn->dn_datablksz && -+ (off > 0 || len < dn->dn_datablksz)) { -+ err = dmu_tx_check_ioerr(NULL, dn, 0, 0); -+ if (err != 0) { -+ txh->txh_tx->tx_err = err; -+ } -+ } -+ } else { -+ zio_t *zio = zio_root(dn->dn_objset->os_spa, -+ NULL, NULL, ZIO_FLAG_CANFAIL); -+ -+ /* first level-0 block */ -+ uint64_t start = off >> dn->dn_datablkshift; -+ if (P2PHASE(off, dn->dn_datablksz) || len < dn->dn_datablksz) { -+ err = dmu_tx_check_ioerr(zio, dn, 0, start); -+ if (err != 0) { -+ txh->txh_tx->tx_err = err; -+ } -+ } -+ -+ err = zio_wait(zio); -+ if (err != 0) { -+ txh->txh_tx->tx_err = err; -+ } -+ } -+} -+ - static void - dmu_tx_count_dnode(dmu_tx_hold_t *txh) - { -@@ -330,6 +377,42 @@ dmu_tx_hold_write_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, int len) - } - } - -+/* -+ * Should be used when appending to an object and the exact offset is unknown. -+ * The write must occur at or beyond the specified offset. Only the L0 block -+ * at provided offset will be prefetched. -+ */ -+void -+dmu_tx_hold_append(dmu_tx_t *tx, uint64_t object, uint64_t off, int len) -+{ -+ dmu_tx_hold_t *txh; -+ -+ ASSERT0(tx->tx_txg); -+ ASSERT3U(len, <=, DMU_MAX_ACCESS); -+ -+ txh = dmu_tx_hold_object_impl(tx, tx->tx_objset, -+ object, THT_APPEND, off, DMU_OBJECT_END); -+ if (txh != NULL) { -+ dmu_tx_count_append(txh, off, len); -+ dmu_tx_count_dnode(txh); -+ } -+} -+ -+void -+dmu_tx_hold_append_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, int len) -+{ -+ dmu_tx_hold_t *txh; -+ -+ ASSERT0(tx->tx_txg); -+ ASSERT3U(len, <=, DMU_MAX_ACCESS); -+ -+ txh = dmu_tx_hold_dnode_impl(tx, dn, THT_APPEND, off, DMU_OBJECT_END); -+ if (txh != NULL) { -+ dmu_tx_count_append(txh, off, len); -+ dmu_tx_count_dnode(txh); -+ } -+} -+ - /* - * This function marks the transaction as being a "net free". The end - * result is that refquotas will be disabled for this transaction, and -@@ -638,6 +721,26 @@ dmu_tx_dirty_buf(dmu_tx_t *tx, dmu_buf_impl_t *db) - if (blkid == 0) - match_offset = TRUE; - break; -+ case THT_APPEND: -+ if (blkid >= beginblk && (blkid <= endblk || -+ txh->txh_arg2 == DMU_OBJECT_END)) -+ match_offset = TRUE; -+ -+ /* -+ * THT_WRITE used for bonus and spill blocks. -+ */ -+ ASSERT(blkid != DMU_BONUS_BLKID && -+ blkid != DMU_SPILL_BLKID); -+ -+ /* -+ * They might have to increase nlevels, -+ * thus dirtying the new TLIBs. Or the -+ * might have to change the block size, -+ * thus dirying the new lvl=0 blk=0. -+ */ -+ if (blkid == 0) -+ match_offset = TRUE; -+ break; - case THT_FREE: - /* - * We will dirty all the level 1 blocks in -@@ -1421,6 +1524,8 @@ dmu_tx_fini(void) - EXPORT_SYMBOL(dmu_tx_create); - EXPORT_SYMBOL(dmu_tx_hold_write); - EXPORT_SYMBOL(dmu_tx_hold_write_by_dnode); -+EXPORT_SYMBOL(dmu_tx_hold_append); -+EXPORT_SYMBOL(dmu_tx_hold_append_by_dnode); - EXPORT_SYMBOL(dmu_tx_hold_free); - EXPORT_SYMBOL(dmu_tx_hold_free_by_dnode); - EXPORT_SYMBOL(dmu_tx_hold_zap); -diff --git a/module/zfs/dsl_deadlist.c b/module/zfs/dsl_deadlist.c -index d5fe2ee56..9827eb147 100644 ---- a/module/zfs/dsl_deadlist.c -+++ b/module/zfs/dsl_deadlist.c -@@ -859,7 +859,7 @@ void - dsl_deadlist_merge(dsl_deadlist_t *dl, uint64_t obj, dmu_tx_t *tx) - { - zap_cursor_t zc, pzc; -- zap_attribute_t za, pza; -+ zap_attribute_t *za, *pza; - dmu_buf_t *bonus; - dsl_deadlist_phys_t *dlp; - dmu_object_info_t doi; -@@ -874,28 +874,31 @@ dsl_deadlist_merge(dsl_deadlist_t *dl, uint64_t obj, dmu_tx_t *tx) - return; - } - -+ za = kmem_alloc(sizeof (*za), KM_SLEEP); -+ pza = kmem_alloc(sizeof (*pza), KM_SLEEP); -+ - mutex_enter(&dl->dl_lock); - /* - * Prefetch up to 128 deadlists first and then more as we progress. - * The limit is a balance between ARC use and diminishing returns. - */ - for (zap_cursor_init(&pzc, dl->dl_os, obj), i = 0; -- (perror = zap_cursor_retrieve(&pzc, &pza)) == 0 && i < 128; -+ (perror = zap_cursor_retrieve(&pzc, pza)) == 0 && i < 128; - zap_cursor_advance(&pzc), i++) { -- dsl_deadlist_prefetch_bpobj(dl, pza.za_first_integer, -- zfs_strtonum(pza.za_name, NULL)); -+ dsl_deadlist_prefetch_bpobj(dl, pza->za_first_integer, -+ zfs_strtonum(pza->za_name, NULL)); - } - for (zap_cursor_init(&zc, dl->dl_os, obj); -- (error = zap_cursor_retrieve(&zc, &za)) == 0; -+ (error = zap_cursor_retrieve(&zc, za)) == 0; - zap_cursor_advance(&zc)) { -- uint64_t mintxg = zfs_strtonum(za.za_name, NULL); -- dsl_deadlist_insert_bpobj(dl, za.za_first_integer, mintxg, tx); -+ uint64_t mintxg = zfs_strtonum(za->za_name, NULL); -+ dsl_deadlist_insert_bpobj(dl, za->za_first_integer, mintxg, tx); - VERIFY0(zap_remove_int(dl->dl_os, obj, mintxg, tx)); - if (perror == 0) { -- dsl_deadlist_prefetch_bpobj(dl, pza.za_first_integer, -- zfs_strtonum(pza.za_name, NULL)); -+ dsl_deadlist_prefetch_bpobj(dl, pza->za_first_integer, -+ zfs_strtonum(pza->za_name, NULL)); - zap_cursor_advance(&pzc); -- perror = zap_cursor_retrieve(&pzc, &pza); -+ perror = zap_cursor_retrieve(&pzc, pza); - } - } - VERIFY3U(error, ==, ENOENT); -@@ -908,6 +911,9 @@ dsl_deadlist_merge(dsl_deadlist_t *dl, uint64_t obj, dmu_tx_t *tx) - bzero(dlp, sizeof (*dlp)); - dmu_buf_rele(bonus, FTAG); - mutex_exit(&dl->dl_lock); -+ -+ kmem_free(za, sizeof (*za)); -+ kmem_free(pza, sizeof (*pza)); - } - - /* -diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c -index f3c639b0d..f0a851ff5 100644 ---- a/module/zfs/dsl_scan.c -+++ b/module/zfs/dsl_scan.c -@@ -37,6 +37,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -126,11 +127,20 @@ static boolean_t scan_ds_queue_contains(dsl_scan_t *scn, uint64_t dsobj, - static void scan_ds_queue_insert(dsl_scan_t *scn, uint64_t dsobj, uint64_t txg); - static void scan_ds_queue_remove(dsl_scan_t *scn, uint64_t dsobj); - static void scan_ds_queue_sync(dsl_scan_t *scn, dmu_tx_t *tx); --static uint64_t dsl_scan_count_data_disks(vdev_t *vd); -+static uint64_t dsl_scan_count_data_disks(spa_t *spa); - - extern int zfs_vdev_async_write_active_min_dirty_percent; - static int zfs_scan_blkstats = 0; - -+/* -+ * 'zpool status' uses bytes processed per pass to report throughput and -+ * estimate time remaining. We define a pass to start when the scanning -+ * phase completes for a sequential resilver. Optionally, this value -+ * may be used to reset the pass statistics every N txgs to provide an -+ * estimated completion time based on currently observed performance. -+ */ -+static uint_t zfs_scan_report_txgs = 0; -+ - /* - * By default zfs will check to ensure it is not over the hard memory - * limit before each txg. If finer-grained control of this is needed -@@ -147,7 +157,7 @@ int zfs_scan_strict_mem_lim = B_FALSE; - * overload the drives with I/O, since that is protected by - * zfs_vdev_scrub_max_active. - */ --unsigned long zfs_scan_vdev_limit = 4 << 20; -+unsigned long zfs_scan_vdev_limit = 16 << 20; - - int zfs_scan_issue_strategy = 0; - int zfs_scan_legacy = B_FALSE; /* don't queue & sort zios, go direct */ -@@ -450,11 +460,12 @@ dsl_scan_init(dsl_pool_t *dp, uint64_t txg) - - /* - * Calculate the max number of in-flight bytes for pool-wide -- * scanning operations (minimum 1MB). Limits for the issuing -- * phase are done per top-level vdev and are handled separately. -+ * scanning operations (minimum 1MB, maximum 1/4 of arc_c_max). -+ * Limits for the issuing phase are done per top-level vdev and -+ * are handled separately. - */ -- scn->scn_maxinflight_bytes = MAX(zfs_scan_vdev_limit * -- dsl_scan_count_data_disks(spa->spa_root_vdev), 1ULL << 20); -+ scn->scn_maxinflight_bytes = MIN(arc_c_max / 4, MAX(1ULL << 20, -+ zfs_scan_vdev_limit * dsl_scan_count_data_disks(spa))); - - avl_create(&scn->scn_queue, scan_ds_queue_compare, sizeof (scan_ds_t), - offsetof(scan_ds_t, sds_node)); -@@ -584,6 +595,8 @@ dsl_scan_init(dsl_pool_t *dp, uint64_t txg) - } - - spa_scan_stat_init(spa); -+ vdev_scan_stat_init(spa->spa_root_vdev); -+ - return (0); - } - -@@ -742,6 +755,7 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx) - scn->scn_last_checkpoint = 0; - scn->scn_checkpointing = B_FALSE; - spa_scan_stat_init(spa); -+ vdev_scan_stat_init(spa->spa_root_vdev); - - if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) { - scn->scn_phys.scn_ddt_class_max = zfs_scrub_ddt_class_max; -@@ -2797,8 +2811,9 @@ dsl_scan_visit(dsl_scan_t *scn, dmu_tx_t *tx) - } - - static uint64_t --dsl_scan_count_data_disks(vdev_t *rvd) -+dsl_scan_count_data_disks(spa_t *spa) - { -+ vdev_t *rvd = spa->spa_root_vdev; - uint64_t i, leaves = 0; - - for (i = 0; i < rvd->vdev_children; i++) { -@@ -3637,6 +3652,16 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx) - return; - } - -+ /* -+ * Disabled by default, set zfs_scan_report_txgs to report -+ * average performance over the last zfs_scan_report_txgs TXGs. -+ */ -+ if (!dsl_scan_is_paused_scrub(scn) && zfs_scan_report_txgs != 0 && -+ tx->tx_txg % zfs_scan_report_txgs == 0) { -+ scn->scn_issued_before_pass += spa->spa_scan_pass_issued; -+ spa_scan_stat_init(spa); -+ } -+ - /* - * It is possible to switch from unsorted to sorted at any time, - * but afterwards the scan will remain sorted unless reloaded from -@@ -3693,12 +3718,13 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx) - taskqid_t prefetch_tqid; - - /* -- * Recalculate the max number of in-flight bytes for pool-wide -- * scanning operations (minimum 1MB). Limits for the issuing -- * phase are done per top-level vdev and are handled separately. -+ * Calculate the max number of in-flight bytes for pool-wide -+ * scanning operations (minimum 1MB, maximum 1/4 of arc_c_max). -+ * Limits for the issuing phase are done per top-level vdev and -+ * are handled separately. - */ -- scn->scn_maxinflight_bytes = MAX(zfs_scan_vdev_limit * -- dsl_scan_count_data_disks(spa->spa_root_vdev), 1ULL << 20); -+ scn->scn_maxinflight_bytes = MIN(arc_c_max / 4, MAX(1ULL << 20, -+ zfs_scan_vdev_limit * dsl_scan_count_data_disks(spa))); - - if (scnp->scn_ddt_bookmark.ddb_class <= - scnp->scn_ddt_class_max) { -@@ -3759,6 +3785,9 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx) - if (scn->scn_is_sorted) { - scn->scn_checkpointing = B_TRUE; - scn->scn_clearing = B_TRUE; -+ scn->scn_issued_before_pass += -+ spa->spa_scan_pass_issued; -+ spa_scan_stat_init(spa); - } - zfs_dbgmsg("scan complete txg %llu", - (longlong_t)tx->tx_txg); -@@ -4485,6 +4514,9 @@ ZFS_MODULE_PARAM(zfs, zfs_, scan_strict_mem_lim, INT, ZMOD_RW, - ZFS_MODULE_PARAM(zfs, zfs_, scan_fill_weight, INT, ZMOD_RW, - "Tunable to adjust bias towards more filled segments during scans"); - -+ZFS_MODULE_PARAM(zfs, zfs_, scan_report_txgs, UINT, ZMOD_RW, -+ "Tunable to report resilver performance over the last N txgs"); -+ - ZFS_MODULE_PARAM(zfs, zfs_, resilver_disable_defer, INT, ZMOD_RW, - "Process all resilvers immediately"); - /* END CSTYLED */ -diff --git a/module/zfs/mmp.c b/module/zfs/mmp.c -index f67a4eb22..139bb0acd 100644 ---- a/module/zfs/mmp.c -+++ b/module/zfs/mmp.c -@@ -444,7 +444,7 @@ mmp_write_uberblock(spa_t *spa) - uint64_t offset; - - hrtime_t lock_acquire_time = gethrtime(); -- spa_config_enter(spa, SCL_STATE, mmp_tag, RW_READER); -+ spa_config_enter_mmp(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/module/zfs/spa.c b/module/zfs/spa.c -index 1ed79eed3..5f238e691 100644 ---- a/module/zfs/spa.c -+++ b/module/zfs/spa.c -@@ -33,6 +33,7 @@ - * Copyright 2017 Joyent, Inc. - * Copyright (c) 2017, Intel Corporation. - * Copyright (c) 2021, Colm Buckley -+ * Copyright (c) 2023 Hewlett Packard Enterprise Development LP. - */ - - /* -@@ -6261,6 +6262,16 @@ spa_tryimport(nvlist_t *tryconfig) - spa->spa_config_source = SPA_CONFIG_SRC_SCAN; - } - -+ /* -+ * spa_import() relies on a pool config fetched by spa_try_import() -+ * for spare/cache devices. Import flags are not passed to -+ * spa_tryimport(), which makes it return early due to a missing log -+ * device and missing retrieving the cache device and spare eventually. -+ * Passing ZFS_IMPORT_MISSING_LOG to spa_tryimport() makes it fetch -+ * the correct configuration regardless of the missing log device. -+ */ -+ spa->spa_import_flags |= ZFS_IMPORT_MISSING_LOG; -+ - error = spa_load(spa, SPA_LOAD_TRYIMPORT, SPA_IMPORT_EXISTING); - - /* -@@ -6747,9 +6758,11 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing, - if (!spa_feature_is_enabled(spa, SPA_FEATURE_DEVICE_REBUILD)) - return (spa_vdev_exit(spa, NULL, txg, ENOTSUP)); - -- if (dsl_scan_resilvering(spa_get_dsl(spa))) -+ if (dsl_scan_resilvering(spa_get_dsl(spa)) || -+ dsl_scan_resilver_scheduled(spa_get_dsl(spa))) { - return (spa_vdev_exit(spa, NULL, txg, - ZFS_ERR_RESILVER_IN_PROGRESS)); -+ } - } else { - if (vdev_rebuild_active(rvd)) - return (spa_vdev_exit(spa, NULL, txg, -@@ -6987,7 +7000,7 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing, - * Detach a device from a mirror or replacing vdev. - * - * If 'replace_done' is specified, only detach if the parent -- * is a replacing vdev. -+ * is a replacing or a spare vdev. - */ - int - spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done) -@@ -7294,6 +7307,10 @@ spa_vdev_initialize_impl(spa_t *spa, uint64_t guid, uint64_t cmd_type, - vd->vdev_initialize_state != VDEV_INITIALIZE_ACTIVE) { - mutex_exit(&vd->vdev_initialize_lock); - return (SET_ERROR(ESRCH)); -+ } else if (cmd_type == POOL_INITIALIZE_UNINIT && -+ vd->vdev_initialize_thread != NULL) { -+ mutex_exit(&vd->vdev_initialize_lock); -+ return (SET_ERROR(EBUSY)); - } - - switch (cmd_type) { -@@ -7306,6 +7323,9 @@ spa_vdev_initialize_impl(spa_t *spa, uint64_t guid, uint64_t cmd_type, - case POOL_INITIALIZE_SUSPEND: - vdev_initialize_stop(vd, VDEV_INITIALIZE_SUSPENDED, vd_list); - break; -+ case POOL_INITIALIZE_UNINIT: -+ vdev_uninitialize(vd); -+ break; - default: - panic("invalid cmd_type %llu", (unsigned long long)cmd_type); - } -@@ -8210,7 +8230,8 @@ spa_async_thread(void *arg) - * If any devices are done replacing, detach them. - */ - if (tasks & SPA_ASYNC_RESILVER_DONE || -- tasks & SPA_ASYNC_REBUILD_DONE) { -+ tasks & SPA_ASYNC_REBUILD_DONE || -+ tasks & SPA_ASYNC_DETACH_SPARE) { - spa_vdev_resilver_done(spa); - } - -diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c -index a57f0727d..113943026 100644 ---- a/module/zfs/spa_misc.c -+++ b/module/zfs/spa_misc.c -@@ -494,8 +494,9 @@ spa_config_tryenter(spa_t *spa, int locks, void *tag, krw_t rw) - return (1); - } - --void --spa_config_enter(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) - { - (void) tag; - int wlocks_held = 0; -@@ -510,7 +511,8 @@ spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw) - continue; - mutex_enter(&scl->scl_lock); - if (rw == RW_READER) { -- while (scl->scl_writer || scl->scl_write_wanted) { -+ while (scl->scl_writer || -+ (!mmp_flag && scl->scl_write_wanted)) { - cv_wait(&scl->scl_cv, &scl->scl_lock); - } - } else { -@@ -528,6 +530,27 @@ spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw) - ASSERT3U(wlocks_held, <=, locks); - } - -+void -+spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw) -+{ -+ spa_config_enter_impl(spa, locks, tag, rw, 0); -+} -+ -+/* -+ * The spa_config_enter_mmp() 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 -+ * a single disk in a pool that is responding slowly and presumably about to -+ * fail. -+ */ -+ -+void -+spa_config_enter_mmp(spa_t *spa, int locks, const void *tag, krw_t rw) -+{ -+ spa_config_enter_impl(spa, locks, tag, rw, 1); -+} -+ - void - spa_config_exit(spa_t *spa, int locks, const void *tag) - { -@@ -2564,7 +2587,6 @@ spa_scan_stat_init(spa_t *spa) - spa->spa_scan_pass_scrub_spent_paused = 0; - spa->spa_scan_pass_exam = 0; - spa->spa_scan_pass_issued = 0; -- vdev_scan_stat_init(spa->spa_root_vdev); - } - - /* -diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c -index 4b9d7e7c0..57259b8ce 100644 ---- a/module/zfs/vdev.c -+++ b/module/zfs/vdev.c -@@ -28,7 +28,7 @@ - * Copyright 2017 Joyent, Inc. - * Copyright (c) 2017, Intel Corporation. - * Copyright (c) 2019, Datto Inc. All rights reserved. -- * Copyright [2021] Hewlett Packard Enterprise Development LP -+ * Copyright (c) 2021, 2023 Hewlett Packard Enterprise Development LP. - */ - - #include -@@ -2645,6 +2645,17 @@ vdev_reopen(vdev_t *vd) - (void) vdev_validate(vd); - } - -+ /* -+ * Recheck if resilver is still needed and cancel any -+ * scheduled resilver if resilver is unneeded. -+ */ -+ if (!vdev_resilver_needed(spa->spa_root_vdev, NULL, NULL) && -+ spa->spa_async_tasks & SPA_ASYNC_RESILVER) { -+ mutex_enter(&spa->spa_async_lock); -+ spa->spa_async_tasks &= ~SPA_ASYNC_RESILVER; -+ mutex_exit(&spa->spa_async_lock); -+ } -+ - /* - * Reassess parent vdev's health. - */ -@@ -3983,11 +3994,18 @@ vdev_remove_wanted(spa_t *spa, uint64_t guid) - return (spa_vdev_state_exit(spa, NULL, SET_ERROR(ENODEV))); - - /* -- * If the vdev is already removed, then don't do anything. -+ * If the vdev is already removed, or expanding which can trigger -+ * repartition add/remove events, then don't do anything. - */ -- if (vd->vdev_removed) -+ if (vd->vdev_removed || vd->vdev_expanding) - return (spa_vdev_state_exit(spa, NULL, 0)); - -+ /* -+ * Confirm the vdev has been removed, otherwise don't do anything. -+ */ -+ if (vd->vdev_ops->vdev_op_leaf && !zio_wait(vdev_probe(vd, NULL))) -+ return (spa_vdev_state_exit(spa, NULL, SET_ERROR(EEXIST))); -+ - vd->vdev_remove_wanted = B_TRUE; - spa_async_request(spa, SPA_ASYNC_REMOVE); - -@@ -4085,9 +4103,19 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate) - - if (wasoffline || - (oldstate < VDEV_STATE_DEGRADED && -- vd->vdev_state >= VDEV_STATE_DEGRADED)) -+ vd->vdev_state >= VDEV_STATE_DEGRADED)) { - spa_event_notify(spa, vd, NULL, ESC_ZFS_VDEV_ONLINE); - -+ /* -+ * Asynchronously detach spare vdev if resilver or -+ * rebuild is not required -+ */ -+ if (vd->vdev_unspare && -+ !dsl_scan_resilvering(spa->spa_dsl_pool) && -+ !dsl_scan_resilver_scheduled(spa->spa_dsl_pool) && -+ !vdev_rebuild_active(tvd)) -+ spa_async_request(spa, SPA_ASYNC_DETACH_SPARE); -+ } - return (spa_vdev_state_exit(spa, vd, 0)); - } - -diff --git a/module/zfs/vdev_initialize.c b/module/zfs/vdev_initialize.c -index 6ffd0d618..5d90fd67c 100644 ---- a/module/zfs/vdev_initialize.c -+++ b/module/zfs/vdev_initialize.c -@@ -100,6 +100,39 @@ vdev_initialize_zap_update_sync(void *arg, dmu_tx_t *tx) - &initialize_state, tx)); - } - -+static void -+vdev_initialize_zap_remove_sync(void *arg, dmu_tx_t *tx) -+{ -+ uint64_t guid = *(uint64_t *)arg; -+ -+ kmem_free(arg, sizeof (uint64_t)); -+ -+ vdev_t *vd = spa_lookup_by_guid(tx->tx_pool->dp_spa, guid, B_FALSE); -+ if (vd == NULL || vd->vdev_top->vdev_removing || !vdev_is_concrete(vd)) -+ return; -+ -+ ASSERT3S(vd->vdev_initialize_state, ==, VDEV_INITIALIZE_NONE); -+ ASSERT3U(vd->vdev_leaf_zap, !=, 0); -+ -+ vd->vdev_initialize_last_offset = 0; -+ vd->vdev_initialize_action_time = 0; -+ -+ objset_t *mos = vd->vdev_spa->spa_meta_objset; -+ int error; -+ -+ error = zap_remove(mos, vd->vdev_leaf_zap, -+ VDEV_LEAF_ZAP_INITIALIZE_LAST_OFFSET, tx); -+ VERIFY(error == 0 || error == ENOENT); -+ -+ error = zap_remove(mos, vd->vdev_leaf_zap, -+ VDEV_LEAF_ZAP_INITIALIZE_STATE, tx); -+ VERIFY(error == 0 || error == ENOENT); -+ -+ error = zap_remove(mos, vd->vdev_leaf_zap, -+ VDEV_LEAF_ZAP_INITIALIZE_ACTION_TIME, tx); -+ VERIFY(error == 0 || error == ENOENT); -+} -+ - static void - vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state) - { -@@ -127,8 +160,14 @@ vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state) - - dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir); - VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); -- dsl_sync_task_nowait(spa_get_dsl(spa), vdev_initialize_zap_update_sync, -- guid, tx); -+ -+ if (new_state != VDEV_INITIALIZE_NONE) { -+ dsl_sync_task_nowait(spa_get_dsl(spa), -+ vdev_initialize_zap_update_sync, guid, tx); -+ } else { -+ dsl_sync_task_nowait(spa_get_dsl(spa), -+ vdev_initialize_zap_remove_sync, guid, tx); -+ } - - switch (new_state) { - case VDEV_INITIALIZE_ACTIVE: -@@ -149,6 +188,10 @@ vdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state) - spa_history_log_internal(spa, "initialize", tx, - "vdev=%s complete", vd->vdev_path); - break; -+ case VDEV_INITIALIZE_NONE: -+ spa_history_log_internal(spa, "uninitialize", tx, -+ "vdev=%s", vd->vdev_path); -+ break; - default: - panic("invalid state %llu", (unsigned long long)new_state); - } -@@ -604,6 +647,24 @@ vdev_initialize(vdev_t *vd) - vdev_initialize_thread, vd, 0, &p0, TS_RUN, maxclsyspri); - } - -+/* -+ * Uninitializes a device. Caller must hold vdev_initialize_lock. -+ * Device must be a leaf and not already be initializing. -+ */ -+void -+vdev_uninitialize(vdev_t *vd) -+{ -+ ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock)); -+ ASSERT(vd->vdev_ops->vdev_op_leaf); -+ ASSERT(vdev_is_concrete(vd)); -+ ASSERT3P(vd->vdev_initialize_thread, ==, NULL); -+ ASSERT(!vd->vdev_detached); -+ ASSERT(!vd->vdev_initialize_exit_wanted); -+ ASSERT(!vd->vdev_top->vdev_removing); -+ -+ vdev_initialize_change_state(vd, VDEV_INITIALIZE_NONE); -+} -+ - /* - * Wait for the initialize thread to be terminated (cancelled or stopped). - */ -@@ -760,6 +821,7 @@ vdev_initialize_restart(vdev_t *vd) - } - - EXPORT_SYMBOL(vdev_initialize); -+EXPORT_SYMBOL(vdev_uninitialize); - EXPORT_SYMBOL(vdev_initialize_stop); - EXPORT_SYMBOL(vdev_initialize_stop_all); - EXPORT_SYMBOL(vdev_initialize_stop_wait); -diff --git a/module/zfs/vdev_rebuild.c b/module/zfs/vdev_rebuild.c -index 9dfbe0cf6..b180fa146 100644 ---- a/module/zfs/vdev_rebuild.c -+++ b/module/zfs/vdev_rebuild.c -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - #include - - /* -@@ -116,13 +117,12 @@ unsigned long zfs_rebuild_max_segment = 1024 * 1024; - * segment size is also large (zfs_rebuild_max_segment=1M). This helps keep - * the queue depth short. - * -- * 32MB was selected as the default value to achieve good performance with -- * a large 90-drive dRAID HDD configuration (draid2:8d:90c:2s). A sequential -- * rebuild was unable to saturate all of the drives using smaller values. -- * With a value of 32MB the sequential resilver write rate was measured at -- * 800MB/s sustained while rebuilding to a distributed spare. -+ * 64MB was observed to deliver the best performance and set as the default. -+ * Testing was performed with a 106-drive dRAID HDD pool (draid2:11d:106c) -+ * and a rebuild rate of 1.2GB/s was measured to the distribute spare. -+ * Smaller values were unable to fully saturate the available pool I/O. - */ --unsigned long zfs_rebuild_vdev_limit = 32 << 20; -+unsigned long zfs_rebuild_vdev_limit = 64 << 20; - - /* - * Automatically start a pool scrub when the last active sequential resilver -@@ -754,6 +754,7 @@ vdev_rebuild_thread(void *arg) - { - vdev_t *vd = arg; - spa_t *spa = vd->vdev_spa; -+ vdev_t *rvd = spa->spa_root_vdev; - int error = 0; - - /* -@@ -786,9 +787,6 @@ vdev_rebuild_thread(void *arg) - vr->vr_pass_bytes_scanned = 0; - vr->vr_pass_bytes_issued = 0; - -- vr->vr_bytes_inflight_max = MAX(1ULL << 20, -- zfs_rebuild_vdev_limit * vd->vdev_children); -- - uint64_t update_est_time = gethrtime(); - vdev_rebuild_update_bytes_est(vd, 0); - -@@ -804,6 +802,17 @@ vdev_rebuild_thread(void *arg) - metaslab_t *msp = vd->vdev_ms[i]; - vr->vr_scan_msp = msp; - -+ /* -+ * Calculate the max number of in-flight bytes for top-level -+ * vdev scanning operations (minimum 1MB, maximum 1/4 of -+ * arc_c_max shared by all top-level vdevs). Limits for the -+ * issuing phase are done per top-level vdev and are handled -+ * separately. -+ */ -+ uint64_t limit = (arc_c_max / 4) / MAX(rvd->vdev_children, 1); -+ vr->vr_bytes_inflight_max = MIN(limit, MAX(1ULL << 20, -+ zfs_rebuild_vdev_limit * vd->vdev_children)); -+ - /* - * Removal of vdevs from the vdev tree may eliminate the need - * for the rebuild, in which case it should be canceled. The -diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c -index a4b391cbe..f441328f3 100644 ---- a/module/zfs/zfs_ioctl.c -+++ b/module/zfs/zfs_ioctl.c -@@ -3985,7 +3985,8 @@ zfs_ioc_pool_initialize(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) - - if (!(cmd_type == POOL_INITIALIZE_CANCEL || - cmd_type == POOL_INITIALIZE_START || -- cmd_type == POOL_INITIALIZE_SUSPEND)) { -+ cmd_type == POOL_INITIALIZE_SUSPEND || -+ cmd_type == POOL_INITIALIZE_UNINIT)) { - return (SET_ERROR(EINVAL)); - } - -diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c -index b9498d17e..0987fd0f7 100644 ---- a/module/zfs/zfs_vnops.c -+++ b/module/zfs/zfs_vnops.c -@@ -68,7 +68,9 @@ zfs_fsync(znode_t *zp, int syncflag, cred_t *cr) - if (zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) { - ZFS_ENTER(zfsvfs); - ZFS_VERIFY_ZP(zp); -+ atomic_inc_32(&zp->z_sync_writes_cnt); - zil_commit(zfsvfs->z_log, zp->z_id); -+ atomic_dec_32(&zp->z_sync_writes_cnt); - ZFS_EXIT(zfsvfs); - } - tsd_set(zfs_fsyncer_key, NULL); -@@ -102,7 +104,7 @@ zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off) - hole = B_FALSE; - - /* Flush any mmap()'d data to disk */ -- if (zn_has_cached_data(zp)) -+ if (zn_has_cached_data(zp, 0, file_sz - 1)) - zn_flush_cached_data(zp, B_FALSE); - - lr = zfs_rangelock_enter(&zp->z_rangelock, 0, UINT64_MAX, RL_READER); -@@ -275,7 +277,8 @@ zfs_read(struct znode *zp, zfs_uio_t *uio, int ioflag, cred_t *cr) - error = mappedread_sf(zp, nbytes, uio); - else - #endif -- if (zn_has_cached_data(zp) && !(ioflag & O_DIRECT)) { -+ if (zn_has_cached_data(zp, zfs_uio_offset(uio), -+ zfs_uio_offset(uio) + nbytes - 1) && !(ioflag & O_DIRECT)) { - error = mappedread(zp, nbytes, uio); - } else { - error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl), -@@ -686,7 +689,8 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr) - zfs_uioskip(uio, nbytes); - tx_bytes = nbytes; - } -- if (tx_bytes && zn_has_cached_data(zp) && -+ if (tx_bytes && -+ zn_has_cached_data(zp, woff, woff + tx_bytes - 1) && - !(ioflag & O_DIRECT)) { - update_pages(zp, woff, tx_bytes, zfsvfs->z_os); - } -diff --git a/module/zfs/zil.c b/module/zfs/zil.c -index aaf509a2f..f2aaeb550 100644 ---- a/module/zfs/zil.c -+++ b/module/zfs/zil.c -@@ -226,11 +226,10 @@ zil_init_log_chain(zilog_t *zilog, blkptr_t *bp) - */ - static int - zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp, -- blkptr_t *nbp, void *dst, char **end) -+ blkptr_t *nbp, char **begin, char **end, arc_buf_t **abuf) - { - enum zio_flag zio_flags = ZIO_FLAG_CANFAIL; - arc_flags_t aflags = ARC_FLAG_WAIT; -- arc_buf_t *abuf = NULL; - zbookmark_phys_t zb; - int error; - -@@ -247,7 +246,7 @@ zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp, - ZB_ZIL_OBJECT, ZB_ZIL_LEVEL, bp->blk_cksum.zc_word[ZIL_ZC_SEQ]); - - error = arc_read(NULL, zilog->zl_spa, bp, arc_getbuf_func, -- &abuf, ZIO_PRIORITY_SYNC_READ, zio_flags, &aflags, &zb); -+ abuf, ZIO_PRIORITY_SYNC_READ, zio_flags, &aflags, &zb); - - if (error == 0) { - zio_cksum_t cksum = bp->blk_cksum; -@@ -262,23 +261,23 @@ zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp, - */ - cksum.zc_word[ZIL_ZC_SEQ]++; - -+ uint64_t size = BP_GET_LSIZE(bp); - if (BP_GET_CHECKSUM(bp) == ZIO_CHECKSUM_ZILOG2) { -- zil_chain_t *zilc = abuf->b_data; -+ zil_chain_t *zilc = (*abuf)->b_data; - char *lr = (char *)(zilc + 1); -- uint64_t len = zilc->zc_nused - sizeof (zil_chain_t); - - if (bcmp(&cksum, &zilc->zc_next_blk.blk_cksum, -- sizeof (cksum)) || BP_IS_HOLE(&zilc->zc_next_blk)) { -+ sizeof (cksum)) || BP_IS_HOLE(&zilc->zc_next_blk) || -+ zilc->zc_nused < sizeof (*zilc) || -+ zilc->zc_nused > size) { - error = SET_ERROR(ECKSUM); - } else { -- ASSERT3U(len, <=, SPA_OLD_MAXBLOCKSIZE); -- bcopy(lr, dst, len); -- *end = (char *)dst + len; -+ *begin = lr; -+ *end = lr + zilc->zc_nused - sizeof (*zilc); - *nbp = zilc->zc_next_blk; - } - } else { -- char *lr = abuf->b_data; -- uint64_t size = BP_GET_LSIZE(bp); -+ char *lr = (*abuf)->b_data; - zil_chain_t *zilc = (zil_chain_t *)(lr + size) - 1; - - if (bcmp(&cksum, &zilc->zc_next_blk.blk_cksum, -@@ -286,15 +285,11 @@ zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp, - (zilc->zc_nused > (size - sizeof (*zilc)))) { - error = SET_ERROR(ECKSUM); - } else { -- ASSERT3U(zilc->zc_nused, <=, -- SPA_OLD_MAXBLOCKSIZE); -- bcopy(lr, dst, zilc->zc_nused); -- *end = (char *)dst + zilc->zc_nused; -+ *begin = lr; -+ *end = lr + zilc->zc_nused; - *nbp = zilc->zc_next_blk; - } - } -- -- arc_buf_destroy(abuf, &abuf); - } - - return (error); -@@ -362,7 +357,6 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, - uint64_t blk_count = 0; - uint64_t lr_count = 0; - blkptr_t blk, next_blk; -- char *lrbuf, *lrp; - int error = 0; - - bzero(&next_blk, sizeof (blkptr_t)); -@@ -382,13 +376,13 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, - * If the log has been claimed, stop if we encounter a sequence - * number greater than the highest claimed sequence number. - */ -- lrbuf = zio_buf_alloc(SPA_OLD_MAXBLOCKSIZE); - zil_bp_tree_init(zilog); - - for (blk = zh->zh_log; !BP_IS_HOLE(&blk); blk = next_blk) { - uint64_t blk_seq = blk.blk_cksum.zc_word[ZIL_ZC_SEQ]; - int reclen; -- char *end = NULL; -+ char *lrp, *end; -+ arc_buf_t *abuf = NULL; - - if (blk_seq > claim_blk_seq) - break; -@@ -404,8 +398,10 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, - break; - - error = zil_read_log_block(zilog, decrypt, &blk, &next_blk, -- lrbuf, &end); -+ &lrp, &end, &abuf); - if (error != 0) { -+ if (abuf) -+ arc_buf_destroy(abuf, &abuf); - if (claimed) { - char name[ZFS_MAX_DATASET_NAME_LEN]; - -@@ -418,7 +414,7 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, - break; - } - -- for (lrp = lrbuf; lrp < end; lrp += reclen) { -+ for (; lrp < end; lrp += reclen) { - lr_t *lr = (lr_t *)lrp; - reclen = lr->lrc_reclen; - ASSERT3U(reclen, >=, sizeof (lr_t)); -@@ -432,6 +428,7 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, - max_lr_seq = lr->lrc_seq; - lr_count++; - } -+ arc_buf_destroy(abuf, &abuf); - } - done: - zilog->zl_parse_error = error; -@@ -441,7 +438,6 @@ done: - zilog->zl_parse_lr_count = lr_count; - - zil_bp_tree_fini(zilog); -- zio_buf_free(lrbuf, SPA_OLD_MAXBLOCKSIZE); - - return (error); - } -@@ -1593,6 +1589,7 @@ zil_lwb_write_issue(zilog_t *zilog, lwb_t *lwb) - wsz = P2ROUNDUP_TYPED(lwb->lwb_nused, ZIL_MIN_BLKSZ, uint64_t); - ASSERT3U(wsz, <=, lwb->lwb_sz); - zio_shrink(lwb->lwb_write_zio, wsz); -+ wsz = lwb->lwb_write_zio->io_size; - - } else { - wsz = lwb->lwb_sz; -@@ -2848,7 +2845,14 @@ static void - zil_commit_itx_assign(zilog_t *zilog, zil_commit_waiter_t *zcw) - { - dmu_tx_t *tx = dmu_tx_create(zilog->zl_os); -- VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); -+ -+ /* -+ * Since we are not going to create any new dirty data, and we -+ * can even help with clearing the existing dirty data, we -+ * should not be subject to the dirty data based delays. We -+ * use TXG_NOTHROTTLE to bypass the delay mechanism. -+ */ -+ VERIFY0(dmu_tx_assign(tx, TXG_WAIT | TXG_NOTHROTTLE)); - - itx_t *itx = zil_itx_create(TX_COMMIT, sizeof (lr_t)); - itx->itx_sync = B_TRUE; -diff --git a/module/zfs/zio.c b/module/zfs/zio.c -index 700f87910..c367ef721 100644 ---- a/module/zfs/zio.c -+++ b/module/zfs/zio.c -@@ -2287,7 +2287,7 @@ zio_nowait(zio_t *zio) - ASSERT3P(zio->io_executor, ==, NULL); - - if (zio->io_child_type == ZIO_CHILD_LOGICAL && -- zio_unique_parent(zio) == NULL) { -+ list_is_empty(&zio->io_parent_list)) { - zio_t *pio; - - /* -diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run -index 554cf96f8..6c2296d4c 100644 ---- a/tests/runfiles/common.run -+++ b/tests/runfiles/common.run -@@ -37,7 +37,7 @@ tests = ['alloc_class_001_pos', 'alloc_class_002_neg', 'alloc_class_003_pos', - 'alloc_class_004_pos', 'alloc_class_005_pos', 'alloc_class_006_pos', - 'alloc_class_007_pos', 'alloc_class_008_pos', 'alloc_class_009_pos', - 'alloc_class_010_pos', 'alloc_class_011_neg', 'alloc_class_012_pos', -- 'alloc_class_013_pos'] -+ 'alloc_class_013_pos', 'alloc_class_014_neg', 'alloc_class_015_pos'] - tags = ['functional', 'alloc_class'] - - [tests/functional/arc] -@@ -407,7 +407,7 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos', - 'import_cachefile_mirror_detached', - 'import_cachefile_paths_changed', - 'import_cachefile_shared_device', -- 'import_devices_missing', -+ 'import_devices_missing', 'import_log_missing', - 'import_paths_changed', - 'import_rewind_config_changed', - 'import_rewind_device_replaced'] -@@ -431,6 +431,7 @@ tests = ['zpool_initialize_attach_detach_add_remove', - 'zpool_initialize_start_and_cancel_neg', - 'zpool_initialize_start_and_cancel_pos', - 'zpool_initialize_suspend_resume', -+ 'zpool_initialize_uninit', - 'zpool_initialize_unsupported_vdevs', - 'zpool_initialize_verify_checksums', - 'zpool_initialize_verify_initialized'] -@@ -456,7 +457,8 @@ tests = ['zpool_replace_001_neg', 'replace-o_ashift', 'replace_prop_ashift'] - tags = ['functional', 'cli_root', 'zpool_replace'] - - [tests/functional/cli_root/zpool_resilver] --tests = ['zpool_resilver_bad_args', 'zpool_resilver_restart'] -+tests = ['zpool_resilver_bad_args', 'zpool_resilver_restart', -+ 'zpool_resilver_concurrent'] - tags = ['functional', 'cli_root', 'zpool_resilver'] - - [tests/functional/cli_root/zpool_scrub] -@@ -669,7 +671,8 @@ tests = ['migration_001_pos', 'migration_002_pos', 'migration_003_pos', - tags = ['functional', 'migration'] - - [tests/functional/mmap] --tests = ['mmap_write_001_pos', 'mmap_read_001_pos', 'mmap_seek_001_pos'] -+tests = ['mmap_mixed', 'mmap_read_001_pos', 'mmap_seek_001_pos', -+ 'mmap_write_001_pos', 'mmap_sync_001_pos'] - tags = ['functional', 'mmap'] - - [tests/functional/mount] -@@ -823,9 +826,9 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos', - 'send-c_mixed_compression', 'send-c_stream_size_estimate', - 'send-c_embedded_blocks', 'send-c_resume', 'send-cpL_varied_recsize', - 'send-c_recv_dedup', 'send-L_toggle', -- 'send_encrypted_incremental.ksh', 'send_encrypted_hierarchy', -- 'send_encrypted_props', 'send_encrypted_truncated_files', -- 'send_freeobjects', 'send_realloc_files', -+ 'send_encrypted_incremental.ksh', 'send_encrypted_freeobjects', -+ 'send_encrypted_hierarchy', 'send_encrypted_props', -+ 'send_encrypted_truncated_files', 'send_freeobjects', 'send_realloc_files', - 'send_realloc_encrypted_files', 'send_spill_block', 'send_holds', - 'send_hole_birth', 'send_mixed_raw', 'send-wR_encrypted_zvol', - 'send_partial_dataset', 'send_invalid', 'send_doall', -diff --git a/tests/runfiles/sanity.run b/tests/runfiles/sanity.run -index fb39fa54b..0a3d42cb2 100644 ---- a/tests/runfiles/sanity.run -+++ b/tests/runfiles/sanity.run -@@ -547,6 +547,7 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos', - 'rsend_014_pos', 'rsend_016_neg', 'send-c_verify_contents', - 'send-c_volume', 'send-c_zstreamdump', 'send-c_recv_dedup', - 'send-L_toggle', 'send_encrypted_hierarchy', 'send_encrypted_props', -+ 'send_encrypted_freeobjects', - 'send_encrypted_truncated_files', 'send_freeobjects', 'send_holds', - 'send_mixed_raw', 'send-wR_encrypted_zvol', 'send_partial_dataset', - 'send_invalid'] -diff --git a/tests/test-runner/bin/test-runner.py.in b/tests/test-runner/bin/test-runner.py.in -index a652d3d4a..5c868d945 100755 ---- a/tests/test-runner/bin/test-runner.py.in -+++ b/tests/test-runner/bin/test-runner.py.in -@@ -33,7 +33,7 @@ from subprocess import PIPE - from subprocess import Popen - from subprocess import check_output - from threading import Timer --from time import time, CLOCK_MONOTONIC_RAW -+from time import time, CLOCK_MONOTONIC - from os.path import exists - - BASEDIR = '/var/tmp/test_results' -@@ -62,7 +62,7 @@ clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] - - def monotonic_time(): - t = timespec() -- if clock_gettime(CLOCK_MONOTONIC_RAW, ctypes.pointer(t)) != 0: -+ if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t)) != 0: - errno_ = ctypes.get_errno() - raise OSError(errno_, os.strerror(errno_)) - return t.tv_sec + t.tv_nsec * 1e-9 -diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in -index 432899c21..878b30025 100755 ---- a/tests/test-runner/bin/zts-report.py.in -+++ b/tests/test-runner/bin/zts-report.py.in -@@ -183,10 +183,13 @@ if sys.platform.startswith('freebsd'): - known.update({ - 'cli_root/zfs_receive/receive-o-x_props_override': - ['FAIL', known_reason], -+ 'cli_root/zpool_resilver/zpool_resilver_concurrent': -+ ['SKIP', na_reason], - 'cli_root/zpool_wait/zpool_wait_trim_basic': ['SKIP', trim_reason], - 'cli_root/zpool_wait/zpool_wait_trim_cancel': ['SKIP', trim_reason], - 'cli_root/zpool_wait/zpool_wait_trim_flag': ['SKIP', trim_reason], - 'link_count/link_count_001': ['SKIP', na_reason], -+ 'mmap/mmap_sync_001_pos': ['SKIP', na_reason], - }) - elif sys.platform.startswith('linux'): - known.update({ -@@ -210,6 +213,7 @@ elif sys.platform.startswith('linux'): - # reasons listed above can be used. - # - maybe = { -+ 'threadsappend/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], -@@ -243,6 +247,7 @@ maybe = { - 'mmp/mmp_on_uberblocks': ['FAIL', known_reason], - 'pyzfs/pyzfs_unittest': ['SKIP', python_deps_reason], - 'pool_checkpoint/checkpoint_discard_busy': ['FAIL', '11946'], -+ 'pam/setup': ['SKIP', "pamtester might be not available"], - 'projectquota/setup': ['SKIP', exec_reason], - 'removal/removal_condense_export': ['FAIL', known_reason], - 'reservation/reservation_008_pos': ['FAIL', '7741'], -@@ -252,14 +257,12 @@ maybe = { - 'snapshot/snapshot_010_pos': ['FAIL', '7961'], - 'snapused/snapused_004_pos': ['FAIL', '5513'], - 'tmpfile/setup': ['SKIP', tmpfile_reason], -- 'threadsappend/threadsappend_001_pos': ['FAIL', '6136'], - 'trim/setup': ['SKIP', trim_reason], - 'upgrade/upgrade_projectquota_001_pos': ['SKIP', project_id_reason], - 'user_namespace/setup': ['SKIP', user_ns_reason], - 'userquota/setup': ['SKIP', exec_reason], -- 'vdev_zaps/vdev_zaps_004_pos': ['FAIL', '6935'], -+ 'vdev_zaps/vdev_zaps_004_pos': ['FAIL', known_reason], - 'zvol/zvol_ENOSPC/zvol_ENOSPC_001_pos': ['FAIL', '5848'], -- 'pam/setup': ['SKIP', "pamtester might be not available"], - } - - if sys.platform.startswith('freebsd'): -@@ -275,12 +278,18 @@ if sys.platform.startswith('freebsd'): - 'resilver/resilver_restart_001': ['FAIL', known_reason], - 'pool_checkpoint/checkpoint_big_rewind': ['FAIL', '12622'], - 'pool_checkpoint/checkpoint_indirect': ['FAIL', '12623'], -+ 'snapshot/snapshot_002_pos': ['FAIL', '14831'], - }) - elif sys.platform.startswith('linux'): - maybe.update({ - 'cli_root/zfs_rename/zfs_rename_002_pos': ['FAIL', known_reason], - 'cli_root/zpool_reopen/zpool_reopen_003_pos': ['FAIL', known_reason], -- 'fault/auto_spare_shared': ['FAIL', '11889'], -+ 'fault/auto_online_002_pos': ['FAIL', 11889], -+ 'fault/auto_replace_001_pos': ['FAIL', 14851], -+ 'fault/auto_spare_002_pos': ['FAIL', 11889], -+ 'fault/auto_spare_multiple': ['FAIL', 11889], -+ 'fault/auto_spare_shared': ['FAIL', 11889], -+ 'fault/decompress_fault': ['FAIL', 11889], - 'io/io_uring': ['SKIP', 'io_uring support required'], - 'limits/filesystem_limit': ['SKIP', known_reason], - 'limits/snapshot_limit': ['SKIP', known_reason], -diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am -index d1c29fcd1..7ec4cb619 100644 ---- a/tests/zfs-tests/cmd/Makefile.am -+++ b/tests/zfs-tests/cmd/Makefile.am -@@ -20,6 +20,7 @@ SUBDIRS = \ - mmap_exec \ - mmap_libaio \ - mmap_seek \ -+ mmap_sync \ - mmapwrite \ - nvlist_to_lua \ - randwritecomp \ -diff --git a/tests/zfs-tests/cmd/mmap_sync/.gitignore b/tests/zfs-tests/cmd/mmap_sync/.gitignore -new file mode 100644 -index 000000000..c721f472b ---- /dev/null -+++ b/tests/zfs-tests/cmd/mmap_sync/.gitignore -@@ -0,0 +1 @@ -+/mmap_sync -diff --git a/tests/zfs-tests/cmd/mmap_sync/Makefile.am b/tests/zfs-tests/cmd/mmap_sync/Makefile.am -new file mode 100644 -index 000000000..313e8db5c ---- /dev/null -+++ b/tests/zfs-tests/cmd/mmap_sync/Makefile.am -@@ -0,0 +1,6 @@ -+include $(top_srcdir)/config/Rules.am -+ -+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin -+ -+pkgexec_PROGRAMS = mmap_sync -+mmap_sync_SOURCES = mmap_sync.c -diff --git a/tests/zfs-tests/cmd/mmap_sync/mmap_sync.c b/tests/zfs-tests/cmd/mmap_sync/mmap_sync.c -new file mode 100644 -index 000000000..226e71be2 ---- /dev/null -+++ b/tests/zfs-tests/cmd/mmap_sync/mmap_sync.c -@@ -0,0 +1,152 @@ -+/* -+ * 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 http://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 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void -+cleanup(char *file) -+{ -+ (void) remove(file); -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ char *testdir = getenv("TESTDIR"); -+ if (!testdir) { -+ fprintf(stderr, "environment variable TESTDIR not set\n"); -+ return (1); -+ } -+ -+ struct stat st; -+ umask(0); -+ if (stat(testdir, &st) != 0 && -+ mkdir(testdir, 0777) != 0) { -+ perror("mkdir"); -+ return (1); -+ } -+ -+ if (argc > 3) { -+ fprintf(stderr, "usage: %s " -+ "[run time in mins] " -+ "[max msync time in ms]\n", argv[0]); -+ return (1); -+ } -+ -+ int run_time_mins = 1; -+ if (argc >= 2) { -+ run_time_mins = atoi(argv[1]); -+ } -+ -+ int max_msync_time_ms = 1000; -+ if (argc >= 3) { -+ max_msync_time_ms = atoi(argv[2]); -+ } -+ -+ char filepath[512]; -+ filepath[0] = '\0'; -+ char *file = &filepath[0]; -+ -+ (void) snprintf(file, 512, "%s/msync_file", testdir); -+ -+ const int LEN = 8; -+ cleanup(file); -+ -+ int fd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | -+ S_IRGRP | S_IROTH); -+ -+ if (fd == -1) { -+ (void) fprintf(stderr, "%s: %s: ", argv[0], file); -+ perror("open"); -+ return (1); -+ } -+ -+ if (ftruncate(fd, LEN) != 0) { -+ perror("ftruncate"); -+ cleanup(file); -+ return (1); -+ } -+ -+ void *ptr = mmap(NULL, LEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ -+ if (ptr == MAP_FAILED) { -+ perror("mmap"); -+ cleanup(file); -+ return (1); -+ } -+ -+ struct timeval tstart; -+ gettimeofday(&tstart, NULL); -+ -+ long long x = 0LL; -+ -+ for (;;) { -+ *((long long *)ptr) = x; -+ x++; -+ -+ struct timeval t1, t2; -+ gettimeofday(&t1, NULL); -+ if (msync(ptr, LEN, MS_SYNC|MS_INVALIDATE) != 0) { -+ perror("msync"); -+ cleanup(file); -+ return (1); -+ } -+ -+ gettimeofday(&t2, NULL); -+ -+ double elapsed = (t2.tv_sec - t1.tv_sec) * 1000.0; -+ elapsed += ((t2.tv_usec - t1.tv_usec) / 1000.0); -+ if (elapsed > max_msync_time_ms) { -+ fprintf(stderr, "slow msync: %f ms\n", elapsed); -+ if (munmap(ptr, LEN) != 0) -+ perror("munmap"); -+ cleanup(file); -+ return (1); -+ } -+ -+ double elapsed_start = (t2.tv_sec - tstart.tv_sec) * 1000.0; -+ elapsed_start += ((t2.tv_usec - tstart.tv_usec) / 1000.0); -+ if (elapsed_start > run_time_mins * 60 * 1000) { -+ break; -+ } -+ } -+ -+ if (munmap(ptr, LEN) != 0) { -+ perror("munmap"); -+ cleanup(file); -+ return (1); -+ } -+ -+ if (close(fd) != 0) { -+ perror("close"); -+ } -+ -+ cleanup(file); -+ return (0); -+} -diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg -index 78802c9fb..8ac38dfd8 100644 ---- a/tests/zfs-tests/include/commands.cfg -+++ b/tests/zfs-tests/include/commands.cfg -@@ -207,6 +207,7 @@ export ZFSTEST_FILES='badsend - mmap_exec - mmap_libaio - mmap_seek -+ mmap_sync - mmapwrite - nvlist_to_lua - randfree_file -diff --git a/tests/zfs-tests/tests/functional/alloc_class/Makefile.am b/tests/zfs-tests/tests/functional/alloc_class/Makefile.am -index 7cffb2eac..82fd9f340 100644 ---- a/tests/zfs-tests/tests/functional/alloc_class/Makefile.am -+++ b/tests/zfs-tests/tests/functional/alloc_class/Makefile.am -@@ -14,7 +14,9 @@ dist_pkgdata_SCRIPTS = \ - alloc_class_010_pos.ksh \ - alloc_class_011_neg.ksh \ - alloc_class_012_pos.ksh \ -- alloc_class_013_pos.ksh -+ alloc_class_013_pos.ksh \ -+ alloc_class_014_neg.ksh \ -+ alloc_class_015_pos.ksh - - dist_pkgdata_DATA = \ - alloc_class.cfg \ -diff --git a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh -index 2ce22a624..790a47f26 100755 ---- a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh -+++ b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_013_pos.ksh -@@ -42,7 +42,8 @@ log_must display_status "$TESTPOOL" - - log_must zfs create -o dedup=on -V 2G $TESTPOOL/$TESTVOL - --log_must eval "new_fs $ZVOL_DEVDIR/$TESTPOOL/$TESTVOL >/dev/null 2>&1" -+block_device_wait "$ZVOL_DEVDIR/$TESTPOOL/$TESTVOL" -+log_must eval "new_fs $ZVOL_DEVDIR/$TESTPOOL/$TESTVOL >/dev/null" - - sync_pool - log_must zpool list -v $TESTPOOL -diff --git a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_014_neg.ksh b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_014_neg.ksh -new file mode 100755 -index 000000000..1b52014fd ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_014_neg.ksh -@@ -0,0 +1,38 @@ -+#!/bin/ksh -p -+ -+# -+# 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. -+# -+ -+. $STF_SUITE/tests/functional/alloc_class/alloc_class.kshlib -+ -+# -+# DESCRIPTION: -+# Setting the special_small_blocks property greater than recordsize fails. -+# -+ -+verify_runnable "global" -+ -+claim="Setting the special_small_blocks property greater than recordsize fails" -+ -+log_assert $claim -+log_onexit cleanup -+log_must disk_setup -+ -+for size in 512 4096 32768 131072 524288 1048576 -+do -+ let bigger=$size*2 -+ log_mustnot zpool create -O recordsize=$size \ -+ -O special_small_blocks=$bigger \ -+ $TESTPOOL raidz $ZPOOL_DISKS special mirror \ -+ $CLASS_DISK0 $CLASS_DISK1 -+done -+ -+log_pass $claim -diff --git a/tests/zfs-tests/tests/functional/alloc_class/alloc_class_015_pos.ksh b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_015_pos.ksh -new file mode 100755 -index 000000000..49c468af6 ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/alloc_class/alloc_class_015_pos.ksh -@@ -0,0 +1,45 @@ -+#!/bin/ksh -p -+ -+# -+# 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. -+# -+ -+. $STF_SUITE/tests/functional/alloc_class/alloc_class.kshlib -+ -+# -+# DESCRIPTION: -+# Can set special_small_blocks property less than or equal to recordsize. -+# -+ -+verify_runnable "global" -+ -+claim="Can set special_small_blocks property less than or equal to recordsize" -+ -+log_assert $claim -+log_onexit cleanup -+log_must disk_setup -+ -+for size in 8192 32768 131072 524288 1048576 -+do -+ let smaller=$size/2 -+ log_must zpool create -O recordsize=$size \ -+ -O special_small_blocks=$smaller \ -+ $TESTPOOL raidz $ZPOOL_DISKS special mirror \ -+ $CLASS_DISK0 $CLASS_DISK1 -+ log_must zpool destroy -f "$TESTPOOL" -+ -+ log_must zpool create -O recordsize=$size \ -+ -O special_small_blocks=$size \ -+ $TESTPOOL raidz $ZPOOL_DISKS special mirror \ -+ $CLASS_DISK0 $CLASS_DISK1 -+ log_must zpool destroy -f "$TESTPOOL" -+done -+ -+log_pass $claim -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am -index a8c9a31dc..4230ec557 100644 ---- a/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am -@@ -12,6 +12,7 @@ dist_pkgdata_SCRIPTS = \ - import_cachefile_paths_changed.ksh \ - import_cachefile_shared_device.ksh \ - import_devices_missing.ksh \ -+ import_log_missing.ksh \ - import_paths_changed.ksh \ - import_rewind_config_changed.ksh \ - import_rewind_device_replaced.ksh \ -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_log_missing.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_log_missing.ksh -new file mode 100755 -index 000000000..f12cac785 ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_import/import_log_missing.ksh -@@ -0,0 +1,75 @@ -+#!/bin/ksh -p -+ -+# -+# 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. -+# -+ -+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.kshlib -+ -+# -+# DESCRIPTION: -+# Import with missing log device should not remove spare/cache. -+# -+# STRATEGY: -+# 1. Create a pool. -+# 2. Add spare, cache and log devices to the pool. -+# 3. Export the pool. -+# 4. Remove the log device. -+# 5. Import the pool with -m flag. -+# 6. Verify that spare and cache are still present in the pool. -+# -+ -+verify_runnable "global" -+ -+log_onexit cleanup -+ -+function test_missing_log -+{ -+ typeset poolcreate="$1" -+ typeset cachevdev="$2" -+ typeset sparevdev="$3" -+ typeset logvdev="$4" -+ typeset missingvdev="$4" -+ -+ log_note "$0: pool '$poolcreate', adding $cachevdev, $sparevdev," \ -+ "$logvdev then moving away $missingvdev." -+ -+ log_must zpool create $TESTPOOL1 $poolcreate -+ -+ log_must zpool add $TESTPOOL1 cache $cachevdev spare $sparevdev \ -+ log $logvdev -+ -+ log_must_busy zpool export $TESTPOOL1 -+ -+ log_must mv $missingvdev $BACKUP_DEVICE_DIR -+ -+ log_must zpool import -m -d $DEVICE_DIR $TESTPOOL1 -+ -+ CACHE_PRESENT=$(zpool status -v $TESTPOOL1 | grep $cachevdev) -+ -+ SPARE_PRESENT=$(zpool status -v $TESTPOOL1 | grep $sparevdev) -+ -+ if [ -z "$CACHE_PRESENT"] || [ -z "SPARE_PRESENT"] -+ then -+ log_fail "cache/spare vdev missing after importing with missing" \ -+ "log device" -+ fi -+ -+ # Cleanup -+ log_must zpool destroy $TESTPOOL1 -+ -+ log_note "" -+} -+ -+log_must mkdir -p $BACKUP_DEVICE_DIR -+ -+test_missing_log "$VDEV0" "$VDEV1" "$VDEV2" "$VDEV3" -+ -+log_pass "zpool import succeeded with missing log device" -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/Makefile.am -index 3968902ec..483c1c2f5 100644 ---- a/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/Makefile.am -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/Makefile.am -@@ -10,6 +10,7 @@ dist_pkgdata_SCRIPTS = \ - zpool_initialize_start_and_cancel_neg.ksh \ - zpool_initialize_start_and_cancel_pos.ksh \ - zpool_initialize_suspend_resume.ksh \ -+ zpool_initialize_uninit.ksh \ - zpool_initialize_unsupported_vdevs.ksh \ - zpool_initialize_verify_checksums.ksh \ - zpool_initialize_verify_initialized.ksh -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/zpool_initialize_uninit.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/zpool_initialize_uninit.ksh -new file mode 100755 -index 000000000..17f776cfb ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_initialize/zpool_initialize_uninit.ksh -@@ -0,0 +1,141 @@ -+#!/bin/ksh -p -+# -+# 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) 2016 by Delphix. All rights reserved. -+# Copyright (C) 2023 Lawrence Livermore National Security, LLC. -+# -+. $STF_SUITE/include/libtest.shlib -+. $STF_SUITE/tests/functional/cli_root/zpool_initialize/zpool_initialize.kshlib -+ -+# -+# DESCRIPTION: -+# Starting, stopping, uninitializing, and restart an initialize works. -+# -+# STRATEGY: -+# 1. Create a one-disk pool. -+# 2. Verify uninitialize succeeds for uninitialized pool. -+# 3. Verify pool wide cancel|suspend + uninit -+# a. Start initializing and verify that initializing is active. -+# b. Verify uninitialize fails when actively initializing. -+# c. Cancel or suspend initializing and verify that initializing is not active. -+# d. Verify uninitialize succeeds after being cancelled. -+# 4. Verify per-disk cancel|suspend + uninit -+# -+ -+DISK1="$(echo $DISKS | cut -d' ' -f1)" -+DISK2="$(echo $DISKS | cut -d' ' -f2)" -+DISK3="$(echo $DISKS | cut -d' ' -f3)" -+ -+function status_check # pool disk1-state disk2-state disk3-state -+{ -+ typeset pool="$1" -+ typeset disk1_state="$2" -+ typeset disk2_state="$3" -+ typeset disk3_state="$4" -+ -+ state=$(zpool status -i "$pool" | grep "$DISK1" | grep "$disk1_state") -+ if [[ -z "$state" ]]; then -+ log_fail "DISK1 state; expected='$disk1_state' got '$state'" -+ fi -+ -+ state=$(zpool status -i "$pool" | grep "$DISK2" | grep "$disk2_state") -+ if [[ -z "$state" ]]; then -+ log_fail "DISK2 state; expected='$disk2_state' got '$state'" -+ fi -+ -+ state=$(zpool status -i "$pool" | grep "$DISK3" | grep "$disk3_state") -+ if [[ -z "$state" ]]; then -+ log_fail "DISK3 state; expected='$disk3_state' got '$state'" -+ fi -+} -+ -+function status_check_all # pool disk-state -+{ -+ typeset pool="$1" -+ typeset disk_state="$2" -+ -+ status_check "$pool" "$disk_state" "$disk_state" "$disk_state" -+} -+ -+# 1. Create a one-disk pool. -+log_must zpool create -f $TESTPOOL $DISK1 $DISK2 $DISK3 -+status_check_all $TESTPOOL "uninitialized" -+ -+# 2. Verify uninitialize succeeds for uninitialized pool. -+log_must zpool initialize -u $TESTPOOL -+status_check_all $TESTPOOL "uninitialized" -+ -+# 3. Verify pool wide cancel + uninit -+log_must zpool initialize $TESTPOOL -+status_check_all $TESTPOOL "[[:digit:]]* initialized" -+ -+log_mustnot zpool initialize -u $TESTPOOL -+status_check_all $TESTPOOL "[[:digit:]]* initialized" -+ -+log_must zpool initialize -c $TESTPOOL -+status_check_all $TESTPOOL "uninitialized" -+ -+log_must zpool initialize -u $TESTPOOL -+status_check_all $TESTPOOL "uninitialized" -+ -+# 3. Verify pool wide suspend + uninit -+log_must zpool initialize $TESTPOOL -+status_check_all $TESTPOOL "[[:digit:]]* initialized" -+ -+log_mustnot zpool initialize -u $TESTPOOL -+status_check_all $TESTPOOL "[[:digit:]]* initialized" -+ -+log_must zpool initialize -s $TESTPOOL -+status_check_all $TESTPOOL "suspended" -+ -+log_must zpool initialize -u $TESTPOOL -+status_check_all $TESTPOOL "uninitialized" -+ -+# 4. Verify per-disk cancel|suspend + uninit -+log_must zpool initialize $TESTPOOL -+status_check_all $TESTPOOL "[[:digit:]]* initialized" -+ -+log_must zpool initialize -c $TESTPOOL $DISK1 -+log_must zpool initialize -s $TESTPOOL $DISK2 -+log_mustnot zpool initialize -u $TESTPOOL $DISK3 -+status_check $TESTPOOL "uninitialized" "suspended" "[[:digit:]]* initialized" -+ -+log_must zpool initialize -u $TESTPOOL $DISK1 -+status_check $TESTPOOL "uninitialized" "suspended" "[[:digit:]]* initialized" -+ -+log_must zpool initialize -u $TESTPOOL $DISK2 -+status_check $TESTPOOL "uninitialized" "uninitialized" "[[:digit:]]* initialized" -+ -+log_must zpool initialize $TESTPOOL $DISK1 -+status_check $TESTPOOL "[[:digit:]]* initialized" "uninitialized" "[[:digit:]]* initialized" -+ -+log_must zpool initialize $TESTPOOL $DISK2 -+status_check_all $TESTPOOL "[[:digit:]]* initialized" -+ -+log_must zpool initialize -s $TESTPOOL -+status_check_all $TESTPOOL "suspended" -+ -+log_must zpool initialize -u $TESTPOOL $DISK1 $DISK2 $DISK3 -+status_check_all $TESTPOOL "uninitialized" -+ -+log_pass "Initialize start + cancel/suspend + uninit + start works" -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/Makefile.am -index 2cec5335f..7ca9e81c1 100644 ---- a/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/Makefile.am -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/Makefile.am -@@ -3,7 +3,8 @@ dist_pkgdata_SCRIPTS = \ - setup.ksh \ - cleanup.ksh \ - zpool_resilver_bad_args.ksh \ -- zpool_resilver_restart.ksh -+ zpool_resilver_restart.ksh \ -+ zpool_resilver_concurrent.ksh - - dist_pkgdata_DATA = \ - zpool_resilver.cfg -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_concurrent.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_concurrent.ksh -new file mode 100755 -index 000000000..4c3b09796 ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_concurrent.ksh -@@ -0,0 +1,101 @@ -+#!/bin/ksh -p -+# -+# 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 http://www.opensolaris.org/os/licensing. -+# 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) 2023 Hewlett Packard Enterprise Development LP. -+# -+ -+. $STF_SUITE/include/libtest.shlib -+. $STF_SUITE/tests/functional/redundancy/redundancy.kshlib -+ -+# -+# DESCRIPTION: -+# Verify 'zpool clear' doesn't cause concurrent resilvers -+# -+# STRATEGY: -+# 1. Create N(10) virtual disk files. -+# 2. Create draid pool based on the virtual disk files. -+# 3. Fill the filesystem with directories and files. -+# 4. Force-fault 2 vdevs and verify distributed spare is kicked in. -+# 5. Free the distributed spare by replacing the faulty drive. -+# 6. Run zpool clear and verify that it does not initiate 2 resilvers -+# concurrently while distributed spare gets kicked in. -+# -+ -+verify_runnable "global" -+ -+typeset -ir devs=10 -+typeset -ir nparity=1 -+typeset -ir ndata=8 -+typeset -ir dspare=1 -+ -+function cleanup -+{ -+ poolexists "$TESTPOOL" && destroy_pool "$TESTPOOL" -+ -+ for i in {0..$devs}; do -+ log_must rm -f "$BASEDIR/vdev$i" -+ done -+ -+ for dir in $BASEDIR; do -+ if [[ -d $dir ]]; then -+ log_must rm -rf $dir -+ fi -+ done -+ -+ zed_stop -+ zed_cleanup -+} -+ -+log_assert "Verify zpool clear on draid pool doesn't cause concurrent resilvers" -+log_onexit cleanup -+ -+setup_test_env $TESTPOOL draid${nparity}:${ndata}d:${dspare}s $devs -+ -+# ZED needed for sequential resilver -+zed_setup -+log_must zed_start -+ -+log_must zpool offline -f $TESTPOOL $BASEDIR/vdev5 -+log_must wait_vdev_state $TESTPOOL draid1-0-0 "ONLINE" 60 -+log_must zpool wait -t resilver $TESTPOOL -+log_must zpool offline -f $TESTPOOL $BASEDIR/vdev6 -+ -+log_must zpool labelclear -f $BASEDIR/vdev5 -+log_must zpool labelclear -f $BASEDIR/vdev6 -+ -+log_must zpool replace -w $TESTPOOL $BASEDIR/vdev5 -+sync_pool $TESTPOOL -+ -+log_must zpool events -c -+log_must zpool clear $TESTPOOL -+log_must wait_vdev_state $TESTPOOL draid1-0-0 "ONLINE" 60 -+log_must zpool wait -t resilver $TESTPOOL -+log_must zpool wait -t scrub $TESTPOOL -+ -+nof_resilver=$(zpool events | grep -c resilver_start) -+if [ $nof_resilver = 1 ] ; then -+ log_must verify_pool $TESTPOOL -+ log_pass "zpool clear on draid pool doesn't cause concurrent resilvers" -+else -+ log_fail "FAIL: sequential and healing resilver initiated concurrently" -+fi -diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh -index fbb0c2910..19781137d 100755 ---- a/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh -+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_trim/zpool_trim_start_and_cancel_pos.ksh -@@ -35,7 +35,7 @@ - DISK1=${DISKS%% *} - - log_must zpool create -f $TESTPOOL $DISK1 --log_must zpool trim $TESTPOOL -+log_must zpool trim -r 1 $TESTPOOL - - [[ -z "$(trim_progress $TESTPOOL $DISK1)" ]] && \ - log_fail "TRIM did not start" -diff --git a/tests/zfs-tests/tests/functional/mmap/Makefile.am b/tests/zfs-tests/tests/functional/mmap/Makefile.am -index b26791ee7..526405954 100644 ---- a/tests/zfs-tests/tests/functional/mmap/Makefile.am -+++ b/tests/zfs-tests/tests/functional/mmap/Makefile.am -@@ -2,10 +2,12 @@ pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/mmap - dist_pkgdata_SCRIPTS = \ - setup.ksh \ - cleanup.ksh \ -+ mmap_mixed.ksh \ - mmap_read_001_pos.ksh \ - mmap_write_001_pos.ksh \ - mmap_libaio_001_pos.ksh \ -- mmap_seek_001_pos.ksh -+ mmap_seek_001_pos.ksh \ -+ mmap_sync_001_pos.ksh - - dist_pkgdata_DATA = \ - mmap.cfg -diff --git a/tests/zfs-tests/tests/functional/mmap/mmap_mixed.ksh b/tests/zfs-tests/tests/functional/mmap/mmap_mixed.ksh -new file mode 100755 -index 000000000..6c8246d48 ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/mmap/mmap_mixed.ksh -@@ -0,0 +1,86 @@ -+#!/bin/ksh -p -+# -+# 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) 2023 by Lawrence Livermore National Security, LLC. -+# -+ -+. $STF_SUITE/include/libtest.shlib -+. $STF_SUITE/tests/functional/mmap/mmap.cfg -+ -+# -+# DESCRIPTION: -+# Verify mixed buffered and mmap IO. -+# -+# STRATEGY: -+# 1. Create an empty file. -+# 2. Start a background buffered read/write fio to the file. -+# 3. Start a background mmap read/write fio to the file. -+# -+ -+verify_runnable "global" -+ -+function cleanup -+{ -+ log_must rm -f "$tmp_file" -+} -+ -+log_assert "Verify mixed buffered and mmap IO" -+ -+log_onexit cleanup -+ -+mntpnt=$(get_prop mountpoint $TESTPOOL/$TESTFS) -+tmp_file=$mntpnt/file -+bs=$((128 * 1024)) -+blocks=64 -+size=$((bs * blocks)) -+runtime=60 -+ -+log_must dd if=/dev/zero of=$tmp_file bs=$bs count=$blocks -+ -+# Buffered IO writes -+log_must eval "fio --filename=$tmp_file --name=buffer-write \ -+ --rw=randwrite --size=$size --bs=$bs --direct=0 --numjobs=1 \ -+ --ioengine=sync --fallocate=none --group_reporting --minimal \ -+ --runtime=$runtime --time_based --norandommap &" -+ -+# Buffered IO reads -+log_must eval "fio --filename=$tmp_file --name=buffer-read \ -+ --rw=randread --size=$size --bs=$bs --direct=0 --numjobs=1 \ -+ --ioengine=sync --fallocate=none --group_reporting --minimal \ -+ --runtime=$runtime --time_based --norandommap &" -+ -+# mmap IO writes -+log_must eval "fio --filename=$tmp_file --name=mmap-write \ -+ --rw=randwrite --size=$size --bs=$bs --numjobs=1 \ -+ --ioengine=mmap --fallocate=none --group_reporting --minimal \ -+ --runtime=$runtime --time_based --norandommap &" -+ -+# mmap IO reads -+log_must eval "fio --filename=$tmp_file --name=mmap-read \ -+ --rw=randread --size=$size --bs=$bs --numjobs=1 \ -+ --ioengine=mmap --fallocate=none --group_reporting --minimal \ -+ --runtime=$runtime --time_based --norandommap &" -+ -+log_must wait -+ -+log_pass "Verfied mixed buffered and mmap IO" -diff --git a/tests/zfs-tests/tests/functional/mmap/mmap_sync_001_pos.ksh b/tests/zfs-tests/tests/functional/mmap/mmap_sync_001_pos.ksh -new file mode 100755 -index 000000000..b764d6607 ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/mmap/mmap_sync_001_pos.ksh -@@ -0,0 +1,63 @@ -+#!/bin/ksh -p -+ -+# -+# 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) 2015, 2016 by Delphix. All rights reserved. -+# -+ -+. $STF_SUITE/include/libtest.shlib -+ -+# -+# DESCRIPTION: -+# msync()s of mmap()'ed file should complete quickly during -+# background dirty page writebacks by the kernel. -+# -+ -+function cleanup -+{ -+ log_must eval "echo $saved_vm_dirty_expire_centisecs > /proc/sys/vm/dirty_expire_centisecs" -+ log_must eval "echo $saved_vm_dirty_background_ratio > /proc/sys/vm/dirty_background_ratio" -+ log_must eval "echo $saved_vm_dirty_writeback_centisecs > /proc/sys/vm/dirty_writeback_centisecs" -+ -+ # revert to some sensible defaults if the values we saved -+ # were incorrect due to a previous run being interrupted -+ if [ $( /proc/sys/vm/dirty_expire_centisecs" -+ fi -+ -+ if [ $( /proc/sys/vm/dirty_background_ratio" -+ fi -+ -+ if [ $( /proc/sys/vm/dirty_writeback_centisecs" -+ fi -+} -+ -+if ! is_linux; then -+ log_unsupported "Only supported on Linux, requires /proc/sys/vm/ tunables" -+fi -+ -+log_onexit cleanup -+log_assert "Run the tests for mmap_sync" -+ -+read -r saved_vm_dirty_expire_centisecs < /proc/sys/vm/dirty_expire_centisecs -+read -r saved_vm_dirty_background_ratio < /proc/sys/vm/dirty_background_ratio -+read -r saved_vm_dirty_writeback_centisecs < /proc/sys/vm/dirty_writeback_centisecs -+ -+log_must eval "echo 1 > /proc/sys/vm/dirty_expire_centisecs" -+log_must eval "echo 1 > /proc/sys/vm/dirty_background_bytes" -+log_must eval "echo 1 > /proc/sys/vm/dirty_writeback_centisecs" -+ -+log_must mmap_sync -+log_pass "mmap_sync tests passed." -diff --git a/tests/zfs-tests/tests/functional/rsend/Makefile.am b/tests/zfs-tests/tests/functional/rsend/Makefile.am -index d80d2124e..2cedf03d3 100644 ---- a/tests/zfs-tests/tests/functional/rsend/Makefile.am -+++ b/tests/zfs-tests/tests/functional/rsend/Makefile.am -@@ -25,6 +25,7 @@ dist_pkgdata_SCRIPTS = \ - rsend_022_pos.ksh \ - rsend_024_pos.ksh \ - send_encrypted_files.ksh \ -+ send_encrypted_freeobjects.ksh \ - send_encrypted_hierarchy.ksh \ - send_encrypted_props.ksh \ - send_encrypted_truncated_files.ksh \ -diff --git a/tests/zfs-tests/tests/functional/rsend/send-c_volume.ksh b/tests/zfs-tests/tests/functional/rsend/send-c_volume.ksh -index 988ed91b9..1bf234823 100755 ---- a/tests/zfs-tests/tests/functional/rsend/send-c_volume.ksh -+++ b/tests/zfs-tests/tests/functional/rsend/send-c_volume.ksh -@@ -29,6 +29,7 @@ - - function cleanup - { -+ rm $BACKDIR/copy - log_must_busy zfs destroy -r $vol - cleanup_pool $POOL2 - } -@@ -60,7 +61,9 @@ log_must eval "zfs recv -d $POOL2 <$BACKDIR/full" - - verify_stream_size $BACKDIR/full $vol - verify_stream_size $BACKDIR/full $vol2 --md5=$(dd if=$voldev2 bs=1024k count=$megs 2>/dev/null | md5digest) -+block_device_wait $voldev2 -+log_must dd if=$voldev2 of=$BACKDIR/copy bs=1024k count=$megs -+md5=$(md5digest $BACKDIR/copy) - [[ $md5 = $md5_1 ]] || log_fail "md5 mismatch: $md5 != $md5_1" - - # Repeat, for an incremental send -@@ -72,7 +75,9 @@ log_must eval "zfs recv -d $POOL2 <$BACKDIR/inc" - - verify_stream_size $BACKDIR/inc $vol 90 $vol@snap - verify_stream_size $BACKDIR/inc $vol2 90 $vol2@snap --md5=$(dd skip=$megs if=$voldev2 bs=1024k count=$megs 2>/dev/null | md5digest) -+block_device_wait $voldev2 -+log_must dd skip=$megs if=$voldev2 of=$BACKDIR/copy bs=1024k count=$megs -+md5=$(md5digest $BACKDIR/copy) - [[ $md5 = $md5_2 ]] || log_fail "md5 mismatch: $md5 != $md5_2" - - log_pass "Verify compressed send works with volumes" -diff --git a/tests/zfs-tests/tests/functional/rsend/send_encrypted_freeobjects.ksh b/tests/zfs-tests/tests/functional/rsend/send_encrypted_freeobjects.ksh -new file mode 100755 -index 000000000..92451bd1a ---- /dev/null -+++ b/tests/zfs-tests/tests/functional/rsend/send_encrypted_freeobjects.ksh -@@ -0,0 +1,87 @@ -+#!/bin/ksh -+ -+# -+# 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) 2017 by Lawrence Livermore National Security, LLC. -+# Copyright (c) 2023 by Findity AB -+# -+ -+. $STF_SUITE/tests/functional/rsend/rsend.kshlib -+ -+# -+# Description: -+# Verify that receiving a raw encrypted stream, with a FREEOBJECTS -+# removing all existing objects in a block followed by an OBJECT write -+# to the same block, does not result in a panic. -+# -+# Strategy: -+# 1. Create a new encrypted filesystem -+# 2. Create file f1 as the first object in some block (here object 128) -+# 3. Take snapshot A -+# 4. Create file f2 as the second object in the same block (here object 129) -+# 5. Delete f1 -+# 6. Take snapshot B -+# 7. Receive a full raw encrypted send of A -+# 8. Receive an incremental raw send of B -+# -+verify_runnable "both" -+ -+function create_object_with_num -+{ -+ file=$1 -+ num=$2 -+ -+ tries=100 -+ for ((i=0; i<$tries; i++)); do -+ touch $file -+ onum=$(ls -li $file | awk '{print $1}') -+ -+ if [[ $onum -ne $num ]] ; then -+ rm -f $file -+ else -+ break -+ fi -+ done -+ if [[ $i -eq $tries ]]; then -+ log_fail "Failed to create object with number $num" -+ fi -+} -+ -+log_assert "FREEOBJECTS followed by OBJECT in encrypted stream does not crash" -+ -+sendds=sendencfods -+recvds=recvencfods -+keyfile=/$POOL/keyencfods -+f1=/$POOL/$sendds/f1 -+f2=/$POOL/$sendds/f2 -+ -+log_must eval "echo 'password' > $keyfile" -+ -+# -+# xattr=sa and dnodesize=legacy for sequential object numbers, see -+# note in send_freeobjects.ksh. -+# -+log_must zfs create -o xattr=sa -o dnodesize=legacy -o encryption=on \ -+ -o keyformat=passphrase -o keylocation=file://$keyfile $POOL/$sendds -+ -+create_object_with_num $f1 128 -+log_must zfs snap $POOL/$sendds@A -+create_object_with_num $f2 129 -+log_must rm $f1 -+log_must zfs snap $POOL/$sendds@B -+ -+log_must eval "zfs send -w $POOL/$sendds@A | zfs recv $POOL/$recvds" -+log_must eval "zfs send -w -i $POOL/$sendds@A $POOL/$sendds@B |" \ -+ "zfs recv $POOL/$recvds" -+ -+log_pass "FREEOBJECTS followed by OBJECT in encrypted stream did not crash" diff --git a/zfs.spec b/zfs.spec index 9167d7a..a415511 100644 --- a/zfs.spec +++ b/zfs.spec @@ -24,21 +24,20 @@ exit 1 %define _duplicate_files_terminate_build 0 -%define rel 1 +%define pre rc3 +%define rel 0.%{pre}.1 %define pname zfs Summary: Native Linux port of the ZFS filesystem Summary(pl.UTF-8): Natywny linuksowy port systemu plików ZFS Name: %{pname}%{?_pld_builder:%{?with_kernel:-kernel}}%{_alt_kernel} -Version: 2.1.11 +Version: 2.2.0 Release: %{rel}%{?_pld_builder:%{?with_kernel:@%{_kernel_ver_str}}} License: CDDL Group: Applications/System -Source0: https://github.com/openzfs/zfs/releases/download/zfs-%{version}/%{pname}-%{version}.tar.gz -# Source0-md5: 2a7b9d2a487a02d373404c48719488ed +Source0: https://github.com/openzfs/zfs/releases/download/zfs-%{version}-%{pre}/%{pname}-%{version}-%{pre}.tar.gz +# Source0-md5: 75fd8dc40d9601db40029b357c824f3f Patch0: initdir.patch -Patch1: am.patch -Patch2: no-Werror.patch -Patch3: staging.patch +Patch3: kernel-6.5.patch URL: https://zfsonlinux.org/ BuildRequires: autoconf >= 2.50 BuildRequires: automake @@ -238,24 +237,8 @@ pakietu kernel%{_alt_kernel} w wersji %{_kernel_ver}.\ \ %files -n kernel%{_alt_kernel}-zfs\ %defattr(644,root,root,755)\ -%dir /lib/modules/%{_kernel_ver}/misc/lua\ -/lib/modules/%{_kernel_ver}/misc/lua/zlua.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/avl\ -/lib/modules/%{_kernel_ver}/misc/avl/zavl.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/icp\ -/lib/modules/%{_kernel_ver}/misc/icp/icp.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/nvpair\ -/lib/modules/%{_kernel_ver}/misc/nvpair/znvpair.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/spl\ -/lib/modules/%{_kernel_ver}/misc/spl/spl.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/unicode\ -/lib/modules/%{_kernel_ver}/misc/unicode/zunicode.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/zcommon\ -/lib/modules/%{_kernel_ver}/misc/zcommon/zcommon.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/zfs\ -/lib/modules/%{_kernel_ver}/misc/zfs/zfs.ko*\ -%dir /lib/modules/%{_kernel_ver}/misc/zstd\ -/lib/modules/%{_kernel_ver}/misc/zstd/zzstd.ko*\ +/lib/modules/%{_kernel_ver}/misc/spl.ko*\ +/lib/modules/%{_kernel_ver}/misc/zfs.ko*\ \ %files -n kernel%{_alt_kernel}-zfs-devel\ %defattr(644,root,root,755)\ @@ -284,18 +267,17 @@ p=`pwd`\ %{?with_kernel:%{expand:%create_kernel_packages}} %prep -%setup -q -n %{pname}-%{version} +%setup -q -n %{pname}-%{version}-%{pre} %patch0 -p1 -%patch1 -p1 -%patch2 -p1 %patch3 -p1 %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+python3(\s|$),#!%{__python3}\1,' \ - cmd/arc_summary/arc_summary3 + cmd/arc_summary %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+@PYTHON_SHEBANG@(\s|$),#!%{__python3}\1,' \ - cmd/arcstat/arcstat.in \ - cmd/dbufstat/dbufstat.in + cmd/arcstat.in \ + cmd/dbufstat.in \ + cmd/zilstat.in %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+bash(\s|$),#!/bin/bash\1,' \ contrib/dracut/02zfsexpandknowledge/module-setup.sh.in \ @@ -347,8 +329,6 @@ rm -rf $RPM_BUILD_ROOT %if %{with kernel} install -d $RPM_BUILD_ROOT cp -a installed/* $RPM_BUILD_ROOT -# Drop unneeded spl compat links -%{__rm} -r $RPM_BUILD_ROOT/usr/src/spl-%{version} %endif %if %{with userspace} @@ -403,6 +383,7 @@ rm -rf $RPM_BUILD_ROOT %attr(755,root,root) %{_bindir}/arc_summary %attr(755,root,root) %{_bindir}/arcstat %attr(755,root,root) %{_bindir}/dbufstat +%attr(755,root,root) %{_bindir}/zilstat %attr(755,root,root) %{_bindir}/zvol_wait %attr(755,root,root) %{_sbindir}/fsck.zfs %attr(755,root,root) %{_sbindir}/zdb @@ -447,6 +428,9 @@ rm -rf $RPM_BUILD_ROOT %{systemdunitdir}/zfs-scrub-monthly@.timer %{systemdunitdir}/zfs-scrub-weekly@.timer %{systemdunitdir}/zfs-share.service +%{systemdunitdir}/zfs-trim-monthly@.timer +%{systemdunitdir}/zfs-trim-weekly@.timer +%{systemdunitdir}/zfs-trim@.service %{systemdunitdir}/zfs-volume-wait.service %{systemdunitdir}/zfs-volumes.target %{systemdunitdir}/zfs-zed.service @@ -471,6 +455,7 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man4/spl.4* %{_mandir}/man4/zfs.4* %{_mandir}/man5/vdev_id.conf.5* +%{_mandir}/man7/vdevprops.7* %{_mandir}/man7/zfsconcepts.7* %{_mandir}/man7/zfsprops.7* %{_mandir}/man7/zpool-features.7* @@ -515,10 +500,12 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man8/zfs-unallow.8* %{_mandir}/man8/zfs-unjail.8* %{_mandir}/man8/zfs-unload-key.8* +%{_mandir}/man8/zfs-unzone.8* %{_mandir}/man8/zfs-unmount.8* %{_mandir}/man8/zfs-upgrade.8* %{_mandir}/man8/zfs-userspace.8* %{_mandir}/man8/zfs-wait.8* +%{_mandir}/man8/zfs-zone.8* %{_mandir}/man8/zfs_ids_to_path.8* %{_mandir}/man8/zgenhostid.8* %{_mandir}/man8/zinject.8* @@ -604,7 +591,7 @@ rm -rf $RPM_BUILD_ROOT %files -n dracut-zfs %defattr(644,root,root,755) -%doc contrib/dracut/README.dracut.markdown +%doc contrib/dracut/README.md %dir %{dracutlibdir}/modules.d/02zfsexpandknowledge %attr(755,root,root) %{dracutlibdir}/modules.d/02zfsexpandknowledge/module-setup.sh %dir %{dracutlibdir}/modules.d/90zfs @@ -649,6 +636,6 @@ rm -rf $RPM_BUILD_ROOT %defattr(644,root,root,755) %dir /usr/src/zfs-%{version} /usr/src/zfs-%{version}/include -/usr/src/zfs-%{version}/zfs.release -/usr/src/zfs-%{version}/zfs_config.h +/usr/src/zfs-%{version}/zfs.release.in +/usr/src/zfs-%{version}/zfs_config.h.in %endif